comp.lang.ada
 help / color / mirror / Atom feed
* Limited use for limited with?
@ 2010-09-28  7:37 Maciej Sobczak
  2010-09-28  9:04 ` Alex R. Mosteo
                   ` (4 more replies)
  0 siblings, 5 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-28  7:37 UTC (permalink / raw)


I have found a problem with the intended application of limited with.

Consider a package specifying some object-oriented construct:

package Objects is

   type Object is interface;
   type Object_Access is access all Object'Class;

   procedure Do_Something (X : in out Object) is abstract;

end Objects;

In such cases I routinely define the XYZ_Access type and later use it
wherever pointers to class-wide XYZ are needed.

Now consider a package that uses the above in a limited way (pun
intended), where only pointers to class-wide type are needed:

with Objects;
package Object_Users is

    procedure Use_Object (X : Objects.Object_Access);

end Object_Users;

The problem is that is some cases it would be more convenient (or just
more self-documenting from the design perspective) to do limited with
instead, but unfortunately this makes Object_Access unavailable. It is
OK to use anonymous access type, at least in some cases like here:

    procedure Use_Object (X : access Objects.Object'Class);

but I find that uncomfortable - after all, the proper access type is
already defined for exactly this purpose.

In such cases, where the design intent is pretty clear (pass around
references to Objects) I find that limited with does not really bring
the functionality that it is supposed to provide. In some more
involving cases I was forced to introduce additional and completely
artificial packages, where limited with would be a perfect fit.

Any thoughts on this?

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-28  7:37 Limited use for limited with? Maciej Sobczak
@ 2010-09-28  9:04 ` Alex R. Mosteo
  2010-09-30  7:24   ` Stephen Leake
  2010-09-28  9:18 ` Ludovic Brenta
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 54+ messages in thread
From: Alex R. Mosteo @ 2010-09-28  9:04 UTC (permalink / raw)


Maciej Sobczak wrote:

> I have found a problem with the intended application of limited with.
> 
> Consider a package specifying some object-oriented construct:
> 
> package Objects is
> 
>    type Object is interface;
>    type Object_Access is access all Object'Class;
> 
>    procedure Do_Something (X : in out Object) is abstract;
> 
> end Objects;
> 
> In such cases I routinely define the XYZ_Access type and later use it
> wherever pointers to class-wide XYZ are needed.
> 
> Now consider a package that uses the above in a limited way (pun
> intended), where only pointers to class-wide type are needed:
> 
> with Objects;
> package Object_Users is
> 
>     procedure Use_Object (X : Objects.Object_Access);
> 
> end Object_Users;
> 
> The problem is that is some cases it would be more convenient (or just
> more self-documenting from the design perspective) to do limited with
> instead, but unfortunately this makes Object_Access unavailable. It is
> OK to use anonymous access type, at least in some cases like here:
> 
>     procedure Use_Object (X : access Objects.Object'Class);
> 
> but I find that uncomfortable - after all, the proper access type is
> already defined for exactly this purpose.
> 
> In such cases, where the design intent is pretty clear (pass around
> references to Objects) I find that limited with does not really bring
> the functionality that it is supposed to provide. In some more
> involving cases I was forced to introduce additional and completely
> artificial packages, where limited with would be a perfect fit.
> 
> Any thoughts on this?

Completely unhelpful on my part -- but my limited (ha) attempts at using 
"limited with" have been a failure. I'm no expert at OO or C++, like you, so 
I can't bring any expertise to the table.

Something that can be of interest in this context is a discussion that 
happened not too long ago (half a year?) in some mailing list -- I thought 
it was the GAP one, but combing the topics I can't find it. People trying to 
do "proper" OO with the new Ada features was complaining about some 
unavoidable quirks. The discussion point was on the truth of "unavoidable". 
I'm failing at locating it, if it rings some bells for someone...

Alex.

> 
> --
> Maciej Sobczak * http://www.inspirel.com




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

* Re: Limited use for limited with?
  2010-09-28  7:37 Limited use for limited with? Maciej Sobczak
  2010-09-28  9:04 ` Alex R. Mosteo
@ 2010-09-28  9:18 ` Ludovic Brenta
  2010-09-28 12:59   ` Maciej Sobczak
                     ` (2 more replies)
  2010-09-28  9:32 ` Vadim Godunko
                   ` (2 subsequent siblings)
  4 siblings, 3 replies; 54+ messages in thread
From: Ludovic Brenta @ 2010-09-28  9:18 UTC (permalink / raw)


Maciej Sobczak wrote on comp.lang.ada:
> I have found a problem with the intended application of limited with.
>
> Consider a package specifying some object-oriented construct:
>
> package Objects is
>
>    type Object is interface;
>    type Object_Access is access all Object'Class;
>
>    procedure Do_Something (X : in out Object) is abstract;
>
> end Objects;
>
> In such cases I routinely define the XYZ_Access type and later use it
> wherever pointers to class-wide XYZ are needed.
>
> Now consider a package that uses the above in a limited way (pun
> intended), where only pointers to class-wide type are needed:
>
> with Objects;
> package Object_Users is
>
>     procedure Use_Object (X : Objects.Object_Access);
>
> end Object_Users;
>
> The problem is that is some cases it would be more convenient (or just
> more self-documenting from the design perspective) to do limited with
> instead, but unfortunately this makes Object_Access unavailable. It is
> OK to use anonymous access type, at least in some cases like here:
>
>     procedure Use_Object (X : access Objects.Object'Class);
>
> but I find that uncomfortable - after all, the proper access type is
> already defined for exactly this purpose.
>
> In such cases, where the design intent is pretty clear (pass around
> references to Objects) I find that limited with does not really bring
> the functionality that it is supposed to provide. In some more
> involving cases I was forced to introduce additional and completely
> artificial packages, where limited with would be a perfect fit.
>
> Any thoughts on this?

I generally think twice or three times before declaring an access type
in the same package as the object type. In fact, I think twice before
declaring any access type at all :) To me, an access type makes the
package unclean.

Since, in Ada, all objects of tagged types are passed by reference and
since Ada has class-wide types, you do not need any access type to
achieve pass-by-reference semantics or dynamic dispatching. This
leaves dynamic memory allocation as the only remaining justification
for access types. If I need dynamic memory allocation, I'd consider
using a container (possibly indefinite) before introducing an access
type. By this reasoning, a general (!) class-wide access type to an
interface (as opposed to a tagged type) may not be justified as you're
never going to dynamically allocate interfaces, only tagged types that
implement the interface.

If, after all these musings, I decide that an access type is really
necessary after all (perhaps because I'm writing my own container),
then I usually declare it where I need the access type, i.e. in
another unit, possibly even in the body. Like so:

package Objects is
   type Object is interface;
   procedure Do_Something (X : in out Object) is abstract;
end Objects;

with Objects;
procedure Client is
   type Object_Access is access Objects.Object'Class; -- not "access
all"
   O : Object_Access := new Objects.Object;
begin
   ...
end Client;

Taking this approach further, I can declare the access type in a
nested scope. When the access type goes out of scope, all objects
allocated through it are deallocated. This is a form of automatic
garbage collection.

If you take this approach, your "limited with" problem will disappear.
As an extra bonus, you can make your package Objects Preelaborated, or
even Pure.

--
Ludovic Brenta.



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

* Re: Limited use for limited with?
  2010-09-28  7:37 Limited use for limited with? Maciej Sobczak
  2010-09-28  9:04 ` Alex R. Mosteo
  2010-09-28  9:18 ` Ludovic Brenta
@ 2010-09-28  9:32 ` Vadim Godunko
  2010-09-28 11:34 ` stefan-lucks
  2010-09-28 16:55 ` Adam Beneschan
  4 siblings, 0 replies; 54+ messages in thread
From: Vadim Godunko @ 2010-09-28  9:32 UTC (permalink / raw)


On Sep 28, 11:37 am, Maciej Sobczak <see.my.homep...@gmail.com> wrote:
>
> In such cases, where the design intent is pretty clear (pass around
> references to Objects) I find that limited with does not really bring
> the functionality that it is supposed to provide.
>
It is how limited with is defined. Ada2012 should relax rules to make
limited with more useful.



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

* Re: Limited use for limited with?
  2010-09-28  7:37 Limited use for limited with? Maciej Sobczak
                   ` (2 preceding siblings ...)
  2010-09-28  9:32 ` Vadim Godunko
@ 2010-09-28 11:34 ` stefan-lucks
  2010-09-28 13:15   ` stefan-lucks
  2010-09-28 16:55 ` Adam Beneschan
  4 siblings, 1 reply; 54+ messages in thread
From: stefan-lucks @ 2010-09-28 11:34 UTC (permalink / raw)


On Tue, 28 Sep 2010, Maciej Sobczak wrote:

> package Objects is
> 
>    type Object is interface;
>    type Object_Access is access all Object'Class;
> 
>    procedure Do_Something (X : in out Object) is abstract;
> 
> end Objects;

[...]
Compiler doesn't like Objects.Object_Access:

>     procedure Use_Object (X : Objects.Object_Access);

[...]
Anymous access works, but is ugly:

>     procedure Use_Object (X : access Objects.Object'Class);

[...]
> Any thoughts on this?

Not an answer to your question -- but what requirements force you to use 
an access type at all? To me, the most natural would be to write 
"X: in out Objects.Object":

limited with Objects;

package Use_Objects is

   procedure Use_1(X: access Objects.Object); -- compiles fine
   procedure Use_2(Y: in out Objects.Object); -- compiles fine
   procedure Use_3(Z: Objects.Object_Access); -- invalid use of incomplete 
type

end Use_Objects;

-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Limited use for limited with?
  2010-09-28  9:18 ` Ludovic Brenta
@ 2010-09-28 12:59   ` Maciej Sobczak
  2010-09-28 13:45     ` Dmitry A. Kazakov
  2010-09-28 15:15     ` Ludovic Brenta
  2010-09-28 15:54   ` Robert A Duff
  2010-09-30  7:27   ` Stephen Leake
  2 siblings, 2 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-28 12:59 UTC (permalink / raw)


On 28 Wrz, 11:18, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:

> I generally think twice or three times before declaring an access type
> in the same package as the object type. In fact, I think twice before
> declaring any access type at all :)

So let's say that I already did the thinking and the most prevalent
use case for access types is callback registration.

Think about AWS dispatchers for the closest analogy.
In fact, the AWS.Server.Start procedure has a version that takes the
callback by access. It is an access to function, but I need it to be
object-oriented.

Hiding the use of access values behind the scenes (by virtue of tagged
types being always passed by reference) would obstruct the code
without clear benefit. This is what AWS does in its other versions of
Start, but I don't like it.

I want to express this:

1. Object is an interface type for the callback that will be
implemented by user.
2. Object_Access is a type that will be used for declaring and passing
around callback references. I don't want everybody to define their own
types for what is a common functionality.

I totally agree that in Ada the pressure for using access values is
much smaller than in C++, but object registration (in a map, perhaps)
is not addressed by any other language feature.

BTW - it is exactly for the fact that there is little need for dynamic
allocation that Object_Access has to be "access all" and not just
"access".

Should I drop the Object_Access type altogether and mess with locally-
defined access types in other parts of the code?

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-28 11:34 ` stefan-lucks
@ 2010-09-28 13:15   ` stefan-lucks
  0 siblings, 0 replies; 54+ messages in thread
From: stefan-lucks @ 2010-09-28 13:15 UTC (permalink / raw)


On Tue, 28 Sep 2010, stefan-lucks@see-the.signature wrote:

>    procedure Use_2(Y: in out Objects.Object); -- compiles fine

Sorry, what I wanted to write is 

     procedure Use_2b(Y: in out Objects.Object'Class);

this also compiles fine.




-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Limited use for limited with?
  2010-09-28 12:59   ` Maciej Sobczak
@ 2010-09-28 13:45     ` Dmitry A. Kazakov
  2010-09-28 21:57       ` Maciej Sobczak
  2010-09-28 15:15     ` Ludovic Brenta
  1 sibling, 1 reply; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-28 13:45 UTC (permalink / raw)


On Tue, 28 Sep 2010 05:59:59 -0700 (PDT), Maciej Sobczak wrote:

> Hiding the use of access values behind the scenes (by virtue of tagged
> types being always passed by reference) would obstruct the code
> without clear benefit.

The benefit is clear - no access types.

> This is what AWS does in its other versions of
> Start, but I don't like it.
> 
> I want to express this:
> 
> 1. Object is an interface type for the callback that will be
> implemented by user.
> 2. Object_Access is a type that will be used for declaring and passing
> around callback references. I don't want everybody to define their own
> types for what is a common functionality.

You should register the object itself rather than its pointer. Use a
constructing function which registers the object by placing it in a list or
do an explicit call to Register. Upon finalization Finalize would remove it
from there. The type of the object must be limited of course. This is the
schema I am using.

> BTW - it is exactly for the fact that there is little need for dynamic
> allocation that Object_Access has to be "access all" and not just
> "access".

I tend to avoid "all" everywhere I can.

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



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

* Re: Limited use for limited with?
  2010-09-28 12:59   ` Maciej Sobczak
  2010-09-28 13:45     ` Dmitry A. Kazakov
@ 2010-09-28 15:15     ` Ludovic Brenta
  2010-09-28 22:04       ` Maciej Sobczak
  1 sibling, 1 reply; 54+ messages in thread
From: Ludovic Brenta @ 2010-09-28 15:15 UTC (permalink / raw)


Maciej Sobczak wrote on comp.lang.ada:
> So let's say that I already did the thinking and the most prevalent
> use case for access types is callback registration.
>
> Think about AWS dispatchers for the closest analogy.
> In fact, the AWS.Server.Start procedure has a version that takes the
> callback by access. It is an access to function, but I need it to be
> object-oriented.

OK, functors then (I believe this word is C++ jargon).

> Hiding the use of access values behind the scenes (by virtue of tagged
> types being always passed by reference) would obstruct the code
> without clear benefit. This is what AWS does in its other versions of
> Start, but I don't like it.

Do you mean you don't like this one:

   procedure Start
     (Web_Server : in out HTTP;
      Dispatcher : Dispatchers.Handler'Class;
      Config     : AWS.Config.Object);

Personally it is the one I prefer. Why do you not like it?

> I want to express this:
>
> 1. Object is an interface type for the callback that will be
> implemented by user.
> 2. Object_Access is a type that will be used for declaring and passing
> around callback references. I don't want everybody to define their own
> types for what is a common functionality.

I don't think this functionality is that common; ideally the only
things you have to do with such references is record them in a
registry and then dereference them to call the callbacks. You wouldn't
"pass around" such references very often, I think. Especially if your
callbacks are allocated at elaboration and not dynamically on the
heap.

> I totally agree that in Ada the pressure for using access values is
> much smaller than in C++, but object registration (in a map, perhaps)
> is not addressed by any other language feature.

I would probably use an instance of Ada.Containers.Indefinite_Vectors
or Indefinite_Doubly_Linked_Lists to hold an ordered list of class-
wide callback objects. Is that the language feature you were looking
for? Granted, such a container would duplicate the callback objects
("functors") in memory; using access values would avoid that.

> Should I drop the Object_Access type altogether and mess with locally-
> defined access types in other parts of the code?

I would define the access type in the package that defines the
registry of callback objects, e.g.

limited with Objects;
package Registry is
   type Callback is access all Objects.Object'Class;
   procedure Register (C : in Callback);
   procedure Call_All_Callbacks_In_Registration_Order;
end Registry;

--
Ludovic Brenta.



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

* Re: Limited use for limited with?
  2010-09-28  9:18 ` Ludovic Brenta
  2010-09-28 12:59   ` Maciej Sobczak
@ 2010-09-28 15:54   ` Robert A Duff
  2010-09-30  7:27   ` Stephen Leake
  2 siblings, 0 replies; 54+ messages in thread
From: Robert A Duff @ 2010-09-28 15:54 UTC (permalink / raw)


Ludovic Brenta <ludovic@ludovic-brenta.org> writes:

> Taking this approach further, I can declare the access type in a
> nested scope. When the access type goes out of scope, all objects
> allocated through it are deallocated. This is a form of automatic
> garbage collection.

Those objects are finalized, but they are not deallocated in
most implementations, unless you use Storage_Pool or
Storage_Size.  I think that's a good thing.

- Bob



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

* Re: Limited use for limited with?
  2010-09-28  7:37 Limited use for limited with? Maciej Sobczak
                   ` (3 preceding siblings ...)
  2010-09-28 11:34 ` stefan-lucks
@ 2010-09-28 16:55 ` Adam Beneschan
  2010-09-28 17:31   ` Robert A Duff
  4 siblings, 1 reply; 54+ messages in thread
From: Adam Beneschan @ 2010-09-28 16:55 UTC (permalink / raw)


On Sep 28, 12:37 am, Maciej Sobczak <see.my.homep...@gmail.com> wrote:
> I have found a problem with the intended application of limited with.
>
> Consider a package specifying some object-oriented construct:
>
> package Objects is
>
>    type Object is interface;
>    type Object_Access is access all Object'Class;
>
>    procedure Do_Something (X : in out Object) is abstract;
>
> end Objects;
>
> In such cases I routinely define the XYZ_Access type and later use it
> wherever pointers to class-wide XYZ are needed.
>
> Now consider a package that uses the above in a limited way (pun
> intended), where only pointers to class-wide type are needed:
>
> with Objects;
> package Object_Users is
>
>     procedure Use_Object (X : Objects.Object_Access);
>
> end Object_Users;
>
> The problem is that is some cases it would be more convenient (or just
> more self-documenting from the design perspective) to do limited with
> instead, but unfortunately this makes Object_Access unavailable. It is
> OK to use anonymous access type, at least in some cases like here:
>
>     procedure Use_Object (X : access Objects.Object'Class);
>
> but I find that uncomfortable - after all, the proper access type is
> already defined for exactly this purpose.
>
> In such cases, where the design intent is pretty clear (pass around
> references to Objects) I find that limited with does not really bring
> the functionality that it is supposed to provide.

I'd recommend that you look at the example in the AI (AI95-217-6):

http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ais/ai-50217.txt

and in particular the !example section.  The example there shows two
packages that depend on each other, using "limited with", but neither
package declares an access type that is an access to a type in the
same package.  Instead, the Employees package declares a named access
type whose designated type is in the Departments package; and the
anonymous access types in both packages all refer to types in the
other package.  So the code that you find "uncomfortable" really *was*
the way it was supposed to work, I think.

I can understand that this solution may not have given you a way to
express things the way you might have preferred.  But doing things
"perfectly" was, I believe, unfeasible.  If you look at the !
discussion part of this AI, you'll realize how much effort the ARG put
into trying to come up with a solution that would provide a reasonable
way to solve a real problem while doing so in a way that could be
implemented feasibly by compilers, and in a way so that precise
language rules could be written and that problems that could arise
from using different combinations of features were addressed.  (Note:
I am not an ARG member and was not part of this effort.)  And then you
have to multiply all that effort by seven, because "limited with" was
just one of *seven* different proposed solutions to the mutual
dependence problem, and all of them received extensive consideration.

So it really rubs me the wrong way to see comments---not from you, but
from someone else---such as "Ada2012 should relax rules to make
limited with more useful."  Perhaps it's because I'm reaching the
Grumpy-Old-Fart-In-Training phase of my life.  But given the amount of
work the ARG put into this over a number of years, can't we at least
assume that they did the best they could to make it as useful as they
could, and that whatever rules are there that you don't like are there
for a very good reason?  Jeesh, now I sound like I'm talking to my
teenager.  Definitely headed for G.O.F. at full speed.

I'm certainly not opposed to people wanting changes in the language
(although it's too late for Ada 2012); but in this case, I'd recommend
that if anyone wants to see this change, they should read the
discussions in all the AI95-217 options (AI95-217-1 through 7) to make
sure they understand all the issues, and then propose something
specific.

OK, I'm done ranting.  For now.

                                -- Adam





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

* Re: Limited use for limited with?
  2010-09-28 16:55 ` Adam Beneschan
@ 2010-09-28 17:31   ` Robert A Duff
  2010-09-28 19:24     ` Adam Beneschan
  0 siblings, 1 reply; 54+ messages in thread
From: Robert A Duff @ 2010-09-28 17:31 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> So it really rubs me the wrong way to see comments---not from you, but
> from someone else---such as "Ada2012 should relax rules to make
> limited with more useful."

Well, ahem, the ARG actually IS considering some changes to
make 'limited with' more useful.  Sorry, I don't remember
the AI number(s).

>...Perhaps it's because I'm reaching the
> Grumpy-Old-Fart-In-Training phase of my life.  But given the amount of
> work the ARG put into this over a number of years, can't we at least
> assume that they did the best they could to make it as useful as they
> could, and that whatever rules are there that you don't like are there
> for a very good reason?

As a member of ARG, I'd like to point out that "lots of hard work"
does not always produce good solutions.  Maybe we all were
confused, and a fresh look would produce something better.

As always, the primary difficulty is remaining compatible
with early versions of the language.  And the second one
is making it implementable by existing compilers, which
were of course designed without knowing about whatever
new rules the ARG is cooking up.  Without those two
concerns, fixing the "cyclic imports" problem is easy.

>...Jeesh, now I sound like I'm talking to my
> teenager.  Definitely headed for G.O.F. at full speed.

;-) ;-)

> I'm certainly not opposed to people wanting changes in the language
> (although it's too late for Ada 2012); but in this case, I'd recommend
> that if anyone wants to see this change, they should read the
> discussions in all the AI95-217 options (AI95-217-1 through 7) to make
> sure they understand all the issues, and then propose something
> specific.

Sure, it's a good idea to look at previous work in the area.
Don't take it as The Ultimate Truth, though.

- Bob



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

* Re: Limited use for limited with?
  2010-09-28 17:31   ` Robert A Duff
@ 2010-09-28 19:24     ` Adam Beneschan
  2010-09-28 20:32       ` Vadim Godunko
  0 siblings, 1 reply; 54+ messages in thread
From: Adam Beneschan @ 2010-09-28 19:24 UTC (permalink / raw)


On Sep 28, 10:31 am, Robert A Duff <bobd...@shell01.TheWorld.com>
wrote:
> Adam Beneschan <a...@irvine.com> writes:
> > So it really rubs me the wrong way to see comments---not from you, but
> > from someone else---such as "Ada2012 should relax rules to make
> > limited with more useful."
>
> Well, ahem, the ARG actually IS considering some changes to
> make 'limited with' more useful.  Sorry, I don't remember
> the AI number(s).

Well, I see some Binding Interpretations related to "limited with".
Most of them seem to be adding missing rules.  I didn't see any AI's
that would relax any rules, and nothing that would make any changes to
the design or have any effect on the feature's usefulness.  Unless, of
course, there are some AI's that have been assigned but haven't yet
made it onto the website.  (There aren't any AI12's yet, I hope??)

I suppose my rant was somewhat over the top.  Sure, ARG makes
mistakes, and it's entirely possible that they started off in a wrong
direction and kept going that way.  Still, there just seems to be
something wrong when one party does a lot of work trying to figure out
what all the issues are and come up with the best solution they can,
and someone else who doesn't understand all the issues says too
facilely, "There's a flaw.  You should change it."  (I'm not talking
about minor and easily fixable flaws like wording errors, some of
which I reported, but "flaws" that necessarily arise because the
designers had to make some compromises and trade-offs.)  I'm not sure
why I'm so sensitive to this, particularly since I didn't do any of
the work on this feature, but I am.

                            -- Adam





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

* Re: Limited use for limited with?
  2010-09-28 19:24     ` Adam Beneschan
@ 2010-09-28 20:32       ` Vadim Godunko
  2010-09-28 21:32         ` Adam Beneschan
  0 siblings, 1 reply; 54+ messages in thread
From: Vadim Godunko @ 2010-09-28 20:32 UTC (permalink / raw)


On Sep 28, 11:24 pm, Adam Beneschan <a...@irvine.com> wrote:
> On Sep 28, 10:31 am, Robert A Duff <bobd...@shell01.TheWorld.com>
> wrote:
>
> > Adam Beneschan <a...@irvine.com> writes:
> > > So it really rubs me the wrong way to see comments---not from you, but
> > > from someone else---such as "Ada2012 should relax rules to make
> > > limited with more useful."
>
May be "should" is wrong word, I am sorry for confusion, but this
extension is in Amendment 2012 right now, see

http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai05s/ai05-0151-1.txt

which allows to use incomplete type as type of parameter of
subprogram, so it covers original issue exactly.



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

* Re: Limited use for limited with?
  2010-09-28 20:32       ` Vadim Godunko
@ 2010-09-28 21:32         ` Adam Beneschan
  0 siblings, 0 replies; 54+ messages in thread
From: Adam Beneschan @ 2010-09-28 21:32 UTC (permalink / raw)


On Sep 28, 1:32 pm, Vadim Godunko <vgodu...@gmail.com> wrote:

> May be "should" is wrong word, I am sorry for confusion, but this
> extension is in Amendment 2012 right now, see
>
> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai05s/ai05-0151-1.txt
>
> which allows to use incomplete type as type of parameter of
> subprogram, so it covers original issue exactly.

My apologies.  I guess I misunderstood you.

                                    -- Adam




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

* Re: Limited use for limited with?
  2010-09-28 13:45     ` Dmitry A. Kazakov
@ 2010-09-28 21:57       ` Maciej Sobczak
  2010-09-29  6:03         ` Ludovic Brenta
  2010-09-29  7:51         ` Dmitry A. Kazakov
  0 siblings, 2 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-28 21:57 UTC (permalink / raw)


On 28 Wrz, 15:45, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Hiding the use of access values behind the scenes (by virtue of tagged
> > types being always passed by reference) would obstruct the code
> > without clear benefit.
>
> The benefit is clear - no access types.

There are still access types. The fact that they are not explicitly
seen in operation signatures just makes it more obscure. No benefit.

Consider:

   procedure Register (X : in Object'Class);

X will be passed by reference, but there is still nothing in the
signature (apart from the name of the operation) that would suggest
that the reference will be leaked out of the operation's scope. So the
user does this:

declare
   X : My_Concrete_Object;
begin
   Register (X);
endl;

and bang, everything breaks into pieces.

Whereas this:

   procedure Register (X : Object_Access);

at least forces the user to think about scopes. I therefore consider
it to be a safer construct.

> You should register the object itself rather than its pointer. Use a
> constructing function which registers the object by placing it in a list or
> do an explicit call to Register.

No way. There are many Registers and it's up to the user to decide
where the given object should be registered; constructor has no such
knowledge.
And *when* it should be registered, which is not necessarily at
construction time.

> I tend to avoid "all" everywhere I can.

Apparently here I cannot.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-28 15:15     ` Ludovic Brenta
@ 2010-09-28 22:04       ` Maciej Sobczak
  0 siblings, 0 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-28 22:04 UTC (permalink / raw)


On 28 Wrz, 17:15, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:

> Do you mean you don't like this one:
>
>    procedure Start
>      (Web_Server : in out HTTP;
>       Dispatcher : Dispatchers.Handler'Class;
>       Config     : AWS.Config.Object);
>
> Personally it is the one I prefer. Why do you not like it?

See my answer to Dmitry for code example. The above construct, by
implicitly leaking references out of its execution, obstructs the
scoping of object lifetime.

> > 1. Object is an interface type for the callback that will be
> > implemented by user.
> > 2. Object_Access is a type that will be used for declaring and passing
> > around callback references. I don't want everybody to define their own
> > types for what is a common functionality.
>
> I don't think this functionality is that common; ideally the only
> things you have to do with such references is record them in a
> registry and then dereference them to call the callbacks. You wouldn't
> "pass around" such references very often, I think. Especially if your
> callbacks are allocated at elaboration and not dynamically on the
> heap.

That's right. Still, I need to express it somehow and I think that
having an explicitly defined access type is a good practice.
Unfortunately it does not seem to be compatible with the "limited
with" feature.

> I would probably use an instance of Ada.Containers.Indefinite_Vectors
> or Indefinite_Doubly_Linked_Lists to hold an ordered list of class-
> wide callback objects. Is that the language feature you were looking
> for? Granted, such a container would duplicate the callback objects
> ("functors") in memory; using access values would avoid that.

Exactly, but copying is not the only problem. There are also
dependencies.
Note that my construct is not dependent on Ada.Containers and it
allows the user to write programs without any use of dynamic memory.
It is perfectly possible to create a callback object at the package
level or local in a subprogram.

> I would define the access type in the package that defines the
> registry of callback objects, e.g.
>
> limited with Objects;
> package Registry is
>    type Callback is access all Objects.Object'Class;
>    procedure Register (C : in Callback);
>    procedure Call_All_Callbacks_In_Registration_Order;
> end Registry;

Interesting. I will have to meditate on this possibility.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-28 21:57       ` Maciej Sobczak
@ 2010-09-29  6:03         ` Ludovic Brenta
  2010-09-29  8:25           ` Maciej Sobczak
  2010-09-29  7:51         ` Dmitry A. Kazakov
  1 sibling, 1 reply; 54+ messages in thread
From: Ludovic Brenta @ 2010-09-29  6:03 UTC (permalink / raw)


Maciej Sobczak writes on comp.lang.ada:
> Consider:
>
>    procedure Register (X : in Object'Class);
>
> X will be passed by reference, but there is still nothing in the
> signature (apart from the name of the operation) that would suggest
> that the reference will be leaked out of the operation's scope. So the
> user does this:
>
> declare
>    X : My_Concrete_Object;
> begin
>    Register (X);
> endl;
>
> and bang, everything breaks into pieces.

No, because this is Ada :)

Suppose Register does something like (where Registry is a suitably
defined indefinite vector):

procedure Register (X : in Object'Class) is
begin
   Registry.Append (X);
end Register;

This does copy a "hidden" reference to X into the Registry, it copies X
itself (i.e. deep copy).  So there is no leak and the construct is safe.
Not so with explicit access values.

-- 
Ludovic Brenta.



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

* Re: Limited use for limited with?
  2010-09-28 21:57       ` Maciej Sobczak
  2010-09-29  6:03         ` Ludovic Brenta
@ 2010-09-29  7:51         ` Dmitry A. Kazakov
  2010-09-29  8:38           ` Maciej Sobczak
  1 sibling, 1 reply; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-29  7:51 UTC (permalink / raw)


On Tue, 28 Sep 2010 14:57:49 -0700 (PDT), Maciej Sobczak wrote:

> On 28 Wrz, 15:45, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> Hiding the use of access values behind the scenes (by virtue of tagged
>>> types being always passed by reference) would obstruct the code
>>> without clear benefit.
>>
>> The benefit is clear - no access types.
> 
> There are still access types. The fact that they are not explicitly
> seen in operation signatures just makes it more obscure.

No, that makes it (the public interface) more clear. Pointer is an
implementation detail to be hidden.

> Consider:
> 
>    procedure Register (X : in Object'Class);
> 
> X will be passed by reference, but there is still nothing in the
> signature (apart from the name of the operation) that would suggest
> that the reference will be leaked out of the operation's scope.

It shall not leak. This is why Finalize has to unregister the object before
killing it.

> So the
> user does this:
> 
> declare
>    X : My_Concrete_Object;
> begin
>    Register (X);
> endl;
> 
> and bang, everything breaks into pieces.

Nothing breaks, X is finalized and removed from the internal list.
 
>> You should register the object itself rather than its pointer. Use a
>> constructing function which registers the object by placing it in a list or
>> do an explicit call to Register.
> 
> No way. There are many Registers and it's up to the user to decide
> where the given object should be registered; constructor has no such
> knowledge.

He decides that upon construction:

declare
   X : Object := Create (My_Repository);

> And *when* it should be registered, which is not necessarily at
> construction time.

A good design rule is that all objects are usable at each point of its
existence. But if unregistered object are OK, then provide a Register
operation:

   procedure Register (X : in out Object, Y : in out Repository'Class);

>> I tend to avoid "all" everywhere I can.
> 
> Apparently here I cannot.

Because you have a model in mind, which treats objects as dynamically
allocated entities. This is a possible design, though it has disadvantages
comparing to scoped object.

But even with this design you don't necessarily need public pointers. You
use handles to objects encapsulating private pointers to privately defined
object types. It is more difficult to pursue in Ada because Ada lacks
delegation (or, alternatively, abstract access type). Nevertheless in Ada
2005 it is quite possible. The idea is that you declare an interface type.
Then you implement it in the handle object and in the private
implementation object. Handle's operation implementation consists of
wrappers.

      Interface
        /       \
       /         \
Handle ---> Object

Object goes into private children packages. Handle's component (pointer to
class-wide) are private. It is quite boring because of the wrappers, and a
combinatorial explosion upon derivation. But I deployed this schema in some
projects.

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



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

* Re: Limited use for limited with?
  2010-09-29  6:03         ` Ludovic Brenta
@ 2010-09-29  8:25           ` Maciej Sobczak
  0 siblings, 0 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-29  8:25 UTC (permalink / raw)


On 29 Wrz, 08:03, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:

> > Consider:
>
> >    procedure Register (X : in Object'Class);
>
> > X will be passed by reference, but there is still nothing in the
> > signature (apart from the name of the operation) that would suggest
> > that the reference will be leaked out of the operation's scope. So the
> > user does this:
>
> > declare
> >    X : My_Concrete_Object;
> > begin
> >    Register (X);
> > endl;
>
> > and bang, everything breaks into pieces.
>
> No, because this is Ada :)
[...]

I was thinking about Register storing the access value somewhere, not
copying the whole object.

The whole idea of registering something is that state changes that are
provoked by the registry are visible to the original creator of the
object. Copying X by value makes no sense in this scenario, because
object updates would not affect the original object. I want to
logically register *my* object, not its copy.

And of course there is still the possibility of Object to be limited
(which is actually the case) - then no deep copy is possible.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-29  7:51         ` Dmitry A. Kazakov
@ 2010-09-29  8:38           ` Maciej Sobczak
  2010-09-29  9:16             ` Dmitry A. Kazakov
  2010-10-05  7:25             ` Randy Brukardt
  0 siblings, 2 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-29  8:38 UTC (permalink / raw)


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

> > There are still access types. The fact that they are not explicitly
> > seen in operation signatures just makes it more obscure.
>
> No, that makes it (the public interface) more clear. Pointer is an
> implementation detail to be hidden.

Reference leak is not an implementation detail, it is a very important
part of the contract.

> > No way. There are many Registers and it's up to the user to decide
> > where the given object should be registered; constructor has no such
> > knowledge.
>
> He decides that upon construction:
>
> declare
>    X : Object := Create (My_Repository);

No way. There are *many* Registers, meaning that a single object can
be registered in several registries, not just one. Will you suggest
passing an array of registries to the constructor? I hope not.

The problem with your approach is that it tries to bend the design of
the system in order to work around some language limitation. I prefer
having it the other way round.

> > And *when* it should be registered, which is not necessarily at
> > construction time.
>
> A good design rule is that all objects are usable at each point of its
> existence. But if unregistered object are OK, then provide a Register
> operation:
>
>    procedure Register (X : in out Object, Y : in out Repository'Class);

And we are back to the beginning. If this uses pointers internally,
then the reference leak is not expressed in the signature. It is
inherently unsafe.
And if it performs deep-copy of X, then it breaks the association with
original object.

> >> I tend to avoid "all" everywhere I can.
>
> > Apparently here I cannot.
>
> Because you have a model in mind, which treats objects as dynamically
> allocated entities.

Not at all. In practice all these objects will be created at library
level or as locals in subprograms (perhaps in the main procedure). No
dynamic memory is needed here, but the ability for objects to refer
each other is still essential.
This is the case where pointers seem to be necessary even though
nothing was allocated dynamically. And that's why we are talking
"access all" here.

> But even with this design you don't necessarily need public pointers. You
> use handles to objects encapsulating private pointers to privately defined
> object types.
[...]

>       Interface
>         /       \
>        /         \
> Handle ---> Object

Sure, but:

- it does not solve the problem, it only changes an explicit problem
into a wrapped problem

- this is exactly what I meant when I said that in more involved
scenario I have to create additional and artificial packages - they
don't correspond to any system design entity


In short, I still don't see a plausible solution to my problem and
from all poor solutions that I'm aware of, the one I already use seems
to be the simplest.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-29  8:38           ` Maciej Sobczak
@ 2010-09-29  9:16             ` Dmitry A. Kazakov
  2010-09-29 12:22               ` Maciej Sobczak
  2010-10-05  7:25             ` Randy Brukardt
  1 sibling, 1 reply; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-29  9:16 UTC (permalink / raw)


On Wed, 29 Sep 2010 01:38:40 -0700 (PDT), Maciej Sobczak wrote:

> On 29 Wrz, 09:51, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> There are still access types. The fact that they are not explicitly
>>> seen in operation signatures just makes it more obscure.
>>
>> No, that makes it (the public interface) more clear. Pointer is an
>> implementation detail to be hidden.
> 
> Reference leak is not an implementation detail, it is a very important
> part of the contract.

It does not leak.

>>> No way. There are many Registers and it's up to the user to decide
>>> where the given object should be registered; constructor has no such
>>> knowledge.
>>
>> He decides that upon construction:
>>
>> declare
>> � �X : Object := Create (My_Repository);
> 
> No way. There are *many* Registers, meaning that a single object can
> be registered in several registries, not just one. Will you suggest
> passing an array of registries to the constructor? I hope not.

If that is the object's property to be registered in multiple lists, e.g.
when the list is static, then yes. Otherwise you register it dynamically.
 
>>> And *when* it should be registered, which is not necessarily at
>>> construction time.
>>
>> A good design rule is that all objects are usable at each point of its
>> existence. But if unregistered object are OK, then provide a Register
>> operation:
>>
>> � �procedure Register (X : in out Object, Y : in out Repository'Class);
> 
> And we are back to the beginning. If this uses pointers internally,
> then the reference leak is not expressed in the signature. It is
> inherently unsafe.

I see no unsafety. References are maintained by the object itself. It is
the safest possible way. [I presume that the scope of the list heads
encloses ones of the objects.]

> And if it performs deep-copy of X, then it breaks the association with
> original object.

No it does not. Object is a limited type.
 
>>>> I tend to avoid "all" everywhere I can.
>>
>>> Apparently here I cannot.
>>
>> Because you have a model in mind, which treats objects as dynamically
>> allocated entities.
> 
> Not at all. In practice all these objects will be created at library
> level or as locals in subprograms (perhaps in the main procedure). No
> dynamic memory is needed here, but the ability for objects to refer
> each other is still essential.

OK, that would be a directed graph. Graphs are doable, but difficult
without pointers, fortunately graphs are very rarely needed.

> In short, I still don't see a plausible solution to my problem and
> from all poor solutions that I'm aware of, the one I already use seems
> to be the simplest.

You didn't state it yet.

The point is that it is a good advise not to expose both referential types
and the object types in public interfaces. You do either of them and hide
another. If that is impossible in some particular cases, that is an Ada
problem, which is better to address, rather than keep on mounting language
kludges, which "limited with" possibly is, IMO.

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



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

* Re: Limited use for limited with?
  2010-09-29  9:16             ` Dmitry A. Kazakov
@ 2010-09-29 12:22               ` Maciej Sobczak
  2010-09-29 13:41                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-29 12:22 UTC (permalink / raw)


On 29 Wrz, 11:16, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> I see no unsafety. References are maintained by the object itself. It is
> the safest possible way. [I presume that the scope of the list heads
> encloses ones of the objects.]

This would create circular dependency between Object and Registry's
internals. That is, Registry refers to Object (to fulfill the design
objective) and Object refers to Registry (to implement the automatic
unregistration). Yuck.

Note also that Object is an interface. I don't control the concrete
implementation - in particular I don't implement the factory
(constructor function). For this reason I cannot do what you propose.
Similarly, I don't implement the finalizer and I don't even want to
impose Controlled on the concrete type - that would not only expose
implementation mess in the public API, but also prevent me from using
interfaces. Good bye multiple inheritance, for example.

The solution that you propose is not only very complex, it also
introduces new problems that would have to be addressed and that would
make the API much more difficult to use.

> The point is that it is a good advise not to expose both referential types
> and the object types in public interfaces.

I don't see any explanation of this advice.
The solution with explicitly defined access types seems to be the
simplest one, as it is the least intrusive with respect to the system
design.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-29 12:22               ` Maciej Sobczak
@ 2010-09-29 13:41                 ` Dmitry A. Kazakov
  2010-09-29 15:07                   ` Georg Bauhaus
  2010-09-29 20:51                   ` Maciej Sobczak
  0 siblings, 2 replies; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-29 13:41 UTC (permalink / raw)


On Wed, 29 Sep 2010 05:22:59 -0700 (PDT), Maciej Sobczak wrote:

> On 29 Wrz, 11:16, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> I see no unsafety. References are maintained by the object itself. It is
>> the safest possible way. [I presume that the scope of the list heads
>> encloses ones of the objects.]
> 
> This would create circular dependency between Object and Registry's
> internals.

You add one derived type to either of the hierarchies and that breaks the
dependency. You have to with or without access types. The dependency is
here, the "limited with" kludge does not remove it.

> That is, Registry refers to Object (to fulfill the design
> objective) and Object refers to Registry (to implement the automatic
> unregistration). Yuck.

Object would call a class-wide operation of Registry from its Finalize.

> Note also that Object is an interface.

I customary derive first abstract root type if I forced to use interfaces
(I dislike interfaces).

> I don't control the concrete
> implementation - in particular I don't implement the factory
> (constructor function).

You declare the factory function abstract to be implemented by derived
types.

> Similarly, I don't implement the finalizer and I don't even want to
> impose Controlled on the concrete type - that would not only expose
> implementation mess in the public API, but also prevent me from using
> interfaces. Good bye multiple inheritance, for example.

That should be decided for each concrete case. Something close to MI could
be achieved by using storage pools. But API infested by pointers is the
worst thing to imagine.

> The solution that you propose is not only very complex,

I don't see how removing a type could add complexity. It didn't add new
operations, it only moved access types elsewhere.

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



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

* Re: Limited use for limited with?
  2010-09-29 13:41                 ` Dmitry A. Kazakov
@ 2010-09-29 15:07                   ` Georg Bauhaus
  2010-09-29 19:22                     ` Dmitry A. Kazakov
  2010-09-29 20:51                   ` Maciej Sobczak
  1 sibling, 1 reply; 54+ messages in thread
From: Georg Bauhaus @ 2010-09-29 15:07 UTC (permalink / raw)


On 29.09.10 15:41, Dmitry A. Kazakov wrote:
> On Wed, 29 Sep 2010 05:22:59 -0700 (PDT), Maciej Sobczak wrote:

>> That is, Registry refers to Object (to fulfill the design
>> objective) and Object refers to Registry (to implement the automatic
>> unregistration). Yuck.
> 
> Object would call a class-wide operation of Registry from its Finalize.

If Object's design needs to be informed about future Registry
objects, how so?

And what about decoupling?


Georg



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

* Re: Limited use for limited with?
  2010-09-29 15:07                   ` Georg Bauhaus
@ 2010-09-29 19:22                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-29 19:22 UTC (permalink / raw)


On Wed, 29 Sep 2010 17:07:01 +0200, Georg Bauhaus wrote:

> On 29.09.10 15:41, Dmitry A. Kazakov wrote:
>> On Wed, 29 Sep 2010 05:22:59 -0700 (PDT), Maciej Sobczak wrote:
> 
>>> That is, Registry refers to Object (to fulfill the design
>>> objective) and Object refers to Registry (to implement the automatic
>>> unregistration). Yuck.
>> 
>> Object would call a class-wide operation of Registry from its Finalize.
> 
> If Object's design needs to be informed about future Registry
> objects, how so?

It need not, and you can dispatch from it anyway.

Since Ada does not have full MD, one of the objects has to be class-wide.
It is difficult to maintain two full-scale hierarchies of Objects and
Registries. Normally the designer is forced to flatten one of them. This is
why absence of MD is damaging to the design, but not in this case.

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



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

* Re: Limited use for limited with?
  2010-09-29 13:41                 ` Dmitry A. Kazakov
  2010-09-29 15:07                   ` Georg Bauhaus
@ 2010-09-29 20:51                   ` Maciej Sobczak
  2010-09-29 21:18                     ` Dmitry A. Kazakov
  2010-10-05  7:35                     ` Randy Brukardt
  1 sibling, 2 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-09-29 20:51 UTC (permalink / raw)


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

> > This would create circular dependency between Object and Registry's
> > internals.
>
> You add one derived type to either of the hierarchies and that breaks the
> dependency. You have to with or without access types.

Not at all. In my design Object knows nothing about registry. There is
no such dependency and therefore it does not have to be broken.
You have introduced this dependency, but this is one of the many
reasons why I don't like your solution.

> The dependency is
> here, the "limited with" kludge does not remove it.

The motivation to use "limited with" came from other reasons, which
are not directly related to registry.

> Object would call a class-wide operation of Registry from its Finalize.

This assumes that Registry is object-oriented and that all registries
have some common interface. I don't want this assumption, it does not
reflect any system requirement.

> > I don't control the concrete
> > implementation - in particular I don't implement the factory
> > (constructor function).
>
> You declare the factory function abstract to be implemented by derived
> types.

And how can I enforce that user will properly use the registry from
the constructor?
I cannot assume this.
I don't even want to impose the existence of any factory functions -
they are not needed as far as Object and Registry are concerned. You
have introduced this concept artificially as part of your solution,
but it does not reflect any design objective. This is yet another
reason why I don't like it.

> > The solution that you propose is not only very complex,
>
> I don't see how removing a type could add complexity.

In order to "remove a type" you have introduced:
- factory functions, perhaps abstract
- Controlled with Finalized
- circular dependencies between Object and Registry (ironically, you
have then proposed to introduce *another derived type* to break that
dependency - does it still count as "removing a type"?)
- common tagged root for all registries (this seems to be also an
additional type)
- storage pools (?)

As far as I'm concerned, your solution evolved to a monster. I
therefore stick to my single access type. :-)

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-09-29 20:51                   ` Maciej Sobczak
@ 2010-09-29 21:18                     ` Dmitry A. Kazakov
  2010-10-05  7:35                     ` Randy Brukardt
  1 sibling, 0 replies; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-09-29 21:18 UTC (permalink / raw)


On Wed, 29 Sep 2010 13:51:53 -0700 (PDT), Maciej Sobczak wrote:

> On 29 Wrz, 15:41, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> This would create circular dependency between Object and Registry's
>>> internals.
>>
>> You add one derived type to either of the hierarchies and that breaks the
>> dependency. You have to with or without access types.
> 
> Not at all. In my design Object knows nothing about registry. There is
> no such dependency and therefore it does not have to be broken.
> You have introduced this dependency, but this is one of the many
> reasons why I don't like your solution.

I did not. You have to pass an object or its pointer to the registry, or a
registry to the object. It is no matter, the operation has two arguments.
The dependency is here.

>> Object would call a class-wide operation of Registry from its Finalize.
> 
> This assumes that Registry is object-oriented and that all registries
> have some common interface. I don't want this assumption, it does not
> reflect any system requirement.

It is not an assumption. All registries are capable to maintain objects.
The set of registry types shares this property, even if you don't introduce
this set as a class, which would be an unwise decision, the class is here.

>>> I don't control the concrete
>>> implementation - in particular I don't implement the factory
>>> (constructor function).
>>
>> You declare the factory function abstract to be implemented by derived
>> types.
> 
> And how can I enforce that user will properly use the registry from
> the constructor?

By hiding other ways to construct the parent type. If the object is
declared with (<>) discriminants and its full view is hidden you have to
use the construction function in the aggregate that creates the object.

>>> The solution that you propose is not only very complex,
>>
>> I don't see how removing a type could add complexity.
> 
> In order to "remove a type" you have introduced:
> - factory functions, perhaps abstract

I don't expose object components anyway. It is a good style to have
components private. If Initialize does not do the job, factory function is
the only choice, because, unfortunately, Ada does not have proper
constructors with parameters.

> - Controlled with Finalized

Same as above. Non-controlled tagged types make no sense, because, again,
Ada lacks constructors and destructors.

> - circular dependencies between Object and Registry (ironically, you
> have then proposed to introduce *another derived type* to break that
> dependency - does it still count as "removing a type"?)

The dependency exists anyway.

[ And it is not circular. The relation "there exists an operation with
arguments of both types" is symmetric. ]

> - common tagged root for all registries (this seems to be also an
> additional type)

A big advantage, because later I might wish to write some class-wide
operations dealing with any registry. It happened to me so many times, that
I practically always use controlled bases.

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



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

* Re: Limited use for limited with?
  2010-09-28  9:04 ` Alex R. Mosteo
@ 2010-09-30  7:24   ` Stephen Leake
  2010-09-30  9:21     ` Alex R. Mosteo
  0 siblings, 1 reply; 54+ messages in thread
From: Stephen Leake @ 2010-09-30  7:24 UTC (permalink / raw)


"Alex R. Mosteo" <alejandro@mosteo.invalid> writes:

> Maciej Sobczak wrote:
>
> Something that can be of interest in this context is a discussion that 
> happened not too long ago (half a year?) in some mailing list -- I thought 
> it was the GAP one, but combing the topics I can't find it. People trying to 
> do "proper" OO with the new Ada features was complaining about some 
> unavoidable quirks. The discussion point was on the truth of "unavoidable". 
> I'm failing at locating it, if it rings some bells for someone...

Perhaps you are thinking of this:

http://groups.google.com/group/comp.lang.ada/browse_thread/thread/7ff1de84a8945e80/664c96862ae388aa?q=Access+types+as+parameters&pli=1

My results are summarized here:

http://www.stephe-leake.org/ada/access_vs_object.html

-- 
-- Stephe



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

* Re: Limited use for limited with?
  2010-09-28  9:18 ` Ludovic Brenta
  2010-09-28 12:59   ` Maciej Sobczak
  2010-09-28 15:54   ` Robert A Duff
@ 2010-09-30  7:27   ` Stephen Leake
  2010-09-30  7:33     ` Ludovic Brenta
  2010-09-30 16:03     ` Adam Beneschan
  2 siblings, 2 replies; 54+ messages in thread
From: Stephen Leake @ 2010-09-30  7:27 UTC (permalink / raw)


Ludovic Brenta <ludovic@ludovic-brenta.org> writes:

> I generally think twice or three times before declaring an access type
> in the same package as the object type. In fact, I think twice before
> declaring any access type at all :) To me, an access type makes the
> package unclean.
>
> Since, in Ada, all objects of tagged types are passed by reference and
> since Ada has class-wide types, you do not need any access type to
> achieve pass-by-reference semantics or dynamic dispatching. This
> leaves dynamic memory allocation as the only remaining justification
> for access types. 

You left out accessibility checks, which are an important reason for
named access types.

-- 
-- Stephe



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

* Re: Limited use for limited with?
  2010-09-30  7:27   ` Stephen Leake
@ 2010-09-30  7:33     ` Ludovic Brenta
  2010-09-30 16:03     ` Adam Beneschan
  1 sibling, 0 replies; 54+ messages in thread
From: Ludovic Brenta @ 2010-09-30  7:33 UTC (permalink / raw)


Stephen Leake wrote on comp.lang.ada:
> Ludovic Brenta <ludo...@ludovic-brenta.org> writes:
>> I generally think twice or three times before declaring an access type
>> in the same package as the object type. In fact, I think twice before
>> declaring any access type at all :) To me, an access type makes the
>> package unclean.
>>
>> Since, in Ada, all objects of tagged types are passed by reference and
>> since Ada has class-wide types, you do not need any access type to
>> achieve pass-by-reference semantics or dynamic dispatching. This
>> leaves dynamic memory allocation as the only remaining justification
>> for access types.
>
> You left out accessibility checks, which are an important reason for
> named access types.

Yes, that's why I generally prefer named access types over anonymous
access types, but you don't use access values just because of
accessibility checks, do you?

--
Ludovic Brenta.



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

* Re: Limited use for limited with?
  2010-09-30  7:24   ` Stephen Leake
@ 2010-09-30  9:21     ` Alex R. Mosteo
  0 siblings, 0 replies; 54+ messages in thread
From: Alex R. Mosteo @ 2010-09-30  9:21 UTC (permalink / raw)


Stephen Leake wrote:

> "Alex R. Mosteo" <alejandro@mosteo.invalid> writes:
> 
>> Maciej Sobczak wrote:
>>
>> Something that can be of interest in this context is a discussion that
>> happened not too long ago (half a year?) in some mailing list -- I
>> thought it was the GAP one, but combing the topics I can't find it.
>> People trying to do "proper" OO with the new Ada features was complaining
>> about some unavoidable quirks. The discussion point was on the truth of
>> "unavoidable". I'm failing at locating it, if it rings some bells for
>> someone...
> 
> Perhaps you are thinking of this:
> 
> 
http://groups.google.com/group/comp.lang.ada/browse_thread/thread/7ff1de84a8945e80/664c96862ae388aa?q=Access+types+as+parameters&pli=1
> 
> My results are summarized here:
> 
> http://www.stephe-leake.org/ada/access_vs_object.html

Although very interesting, that was not the one. There were some guys 
teaching OO with Ada (perhaps one of them was Italian?)...




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

* Re: Limited use for limited with?
  2010-09-30  7:27   ` Stephen Leake
  2010-09-30  7:33     ` Ludovic Brenta
@ 2010-09-30 16:03     ` Adam Beneschan
  2010-10-07 11:55       ` Stephen Leake
  1 sibling, 1 reply; 54+ messages in thread
From: Adam Beneschan @ 2010-09-30 16:03 UTC (permalink / raw)


On Sep 30, 12:27 am, Stephen Leake <stephen_le...@stephe-leake.org>
wrote:
> Ludovic Brenta <ludo...@ludovic-brenta.org> writes:
> > I generally think twice or three times before declaring an access type
> > in the same package as the object type. In fact, I think twice before
> > declaring any access type at all :) To me, an access type makes the
> > package unclean.
>
> > Since, in Ada, all objects of tagged types are passed by reference and
> > since Ada has class-wide types, you do not need any access type to
> > achieve pass-by-reference semantics or dynamic dispatching. This
> > leaves dynamic memory allocation as the only remaining justification
> > for access types.
>
> You left out accessibility checks, which are an important reason for
> named access types.

Really?  Most uses of anonymous access types still involve
accessibility checks.  The main case where they don't is access
parameters; and in that case, you usually don't want accessibility
checks unless you're going to store the parameter somewhere where it
could live after the subprogram is completed, and doing so is going to
involve an accessibility check at the point where it's stored, whether
or not the type of the stored data is named or anonymous.  This should
all be crystal clear from reading 3.10.2.

(I'm kidding about that last.  Nothing about 3.10.2 is clear.  The
only reason I recommend reading 3.10.2 is because I own stock in
Advil.)

                                      -- Adam



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

* Re: Limited use for limited with?
  2010-09-29  8:38           ` Maciej Sobczak
  2010-09-29  9:16             ` Dmitry A. Kazakov
@ 2010-10-05  7:25             ` Randy Brukardt
  2010-10-08  8:23               ` Maciej Sobczak
  1 sibling, 1 reply; 54+ messages in thread
From: Randy Brukardt @ 2010-10-05  7:25 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:292dd0bd-1fc4-4715-bb70-7655d0dc04eb@j24g2000yqa.googlegroups.com...
On 29 Wrz, 09:51, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
>> No, that makes it (the public interface) more clear. Pointer is an
>> implementation detail to be hidden.
>
>Reference leak is not an implementation detail, it is a very important
>part of the contract.

Dmitry is right, the *reference* ought to be part of the object, so a leak 
is impossible. In any case, using an access type in the specification of 
Register doesn't do anything to say how long the access will be used for, so 
that doesn't help any. (C and C++ interfaces are notorious for this problem: 
there is often no way to tell whether the access needs to remain valid until 
some later time, nor what time that is.)

>No way. There are *many* Registers, meaning that a single object can
>be registered in several registries, not just one. Will you suggest
>passing an array of registries to the constructor? I hope not.

This sounds like chaos, not a design. There is no way to figure out anything 
that happens with callbacks, registered or not. Callbacks are dubious to 
begin with; moreover, when objects need to be registered that should only 
happen with a very small number of places (hopefully one).

Note that Claw uses exactly the design that Dmitry is describing. Each 
Window can be linked into a handful of data structures -- but we use 
Finalize to ensure it is not linked on any when the object is destroyed. The 
alternative of making all of this the client's problem is simply not "the 
Ada way". (It also would have made Claw technical support impossible; we had 
plenty of bizarre problems even with all of the automatic cleanup, some 
because compiler bugs didn't always clean things up. Without that cleanup, 
it would have been total chaos -- it is viritually impossible to manually 
clean up objects when exceptions happen [some are always missed] -- and 
exceptions are *always* happening in an Ada program [especially during 
testing].)

>The problem with your approach is that it tries to bend the design of
>the system in order to work around some language limitation. I prefer
>having it the other way round.

The "design" sounds more like copying bad ideas from some other 
implementation for some other programming language.

>In short, I still don't see a plausible solution to my problem and
>from all poor solutions that I'm aware of, the one I already use seems
>to be the simplest.

When you start with a poor design, it's not surprising you can only find 
poor solutions...

                                Randy.





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

* Re: Limited use for limited with?
  2010-09-29 20:51                   ` Maciej Sobczak
  2010-09-29 21:18                     ` Dmitry A. Kazakov
@ 2010-10-05  7:35                     ` Randy Brukardt
  2010-10-08  8:05                       ` Maciej Sobczak
  1 sibling, 1 reply; 54+ messages in thread
From: Randy Brukardt @ 2010-10-05  7:35 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:f059316d-9994-4ea4-b984-f9530768bfbc@d25g2000yqc.googlegroups.com...
...
> Not at all. In my design Object knows nothing about registry. There is
> no such dependency and therefore it does not have to be broken.

But the Registries are completely unsafe! They have no way to protect 
against dangling pointers, so any client mistake (and clients make *lots* of 
mistakes) will cause the entire system to crash or malfunction. (And this 
will be the worst kind of crash, with no possible way to finding where it 
came from, since the crash will occur long after the actual error and not be 
tied to it in any way.)

It's always better to prevent abuse in the interface. And in this case, I 
don't think you have any choice unless you are willing to assume that your 
clients are perfect (ha!). Storing arbitrary general access values is no 
safer than storing a link to an object without finalization protection. You 
shouldn't do either one of them.

Unless you like to spend many hours in a debugger, single-stepping your 
code, you will find some way to protect the registries against the 
possibility of dangling pointers. And that is going to require some sort of 
cooperation (or deep copies, which I agree will often not work).

                              Randy.





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

* Re: Limited use for limited with?
  2010-09-30 16:03     ` Adam Beneschan
@ 2010-10-07 11:55       ` Stephen Leake
  2010-10-07 18:27         ` Martin Krischik
  0 siblings, 1 reply; 54+ messages in thread
From: Stephen Leake @ 2010-10-07 11:55 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> On Sep 30, 12:27 am, Stephen Leake <stephen_le...@stephe-leake.org>
> wrote:
>> Ludovic Brenta <ludo...@ludovic-brenta.org> writes:
>> > I generally think twice or three times before declaring an access type
>> > in the same package as the object type. In fact, I think twice before
>> > declaring any access type at all :) To me, an access type makes the
>> > package unclean.
>>
>> > Since, in Ada, all objects of tagged types are passed by reference and
>> > since Ada has class-wide types, you do not need any access type to
>> > achieve pass-by-reference semantics or dynamic dispatching. This
>> > leaves dynamic memory allocation as the only remaining justification
>> > for access types.
>>
>> You left out accessibility checks, which are an important reason for
>> named access types.
>
> Really?  Most uses of anonymous access types still involve
> accessibility checks.  

Yes, and that's the point. 

> The main case where they don't is access parameters; and in that case,
> you usually don't want accessibility checks unless you're going to
> store the parameter somewhere where it could live after the subprogram
> is completed, and doing so is going to involve an accessibility check
> at the point where it's stored, whether or not the type of the stored
> data is named or anonymous. 

Exactly. Suppose we have the following:

type My_Type is record ... end record;
type My_Access_Type is access all My_Type;

procedure Foo_One (A : access My_Type);

procedure Foo_Two (A : My_Access_Type);


Inside Foo_Two, we know that the accessibility level of A is the same as
the declaration of My_Access_Type, so you can save it to any value of
that type; the accessibility check will pass (and should be removed by
an optimizing compiler). Inside Foo_One, the accessibility level of A is
likely the point of the call; it is not safe to save it, since you have
no control over how the caller has declared the actual for A.

So if you need to save copies of pointers, you need named access types,
so you can know ahead of time that the accessibility check will not fail.


In Ada 2012, it may be possible to use preconditions to enforce
accessibility requirements; that would allow some more uses of anonymous
access parameters.

-- 
-- Stephe



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

* Re: Limited use for limited with?
  2010-10-07 11:55       ` Stephen Leake
@ 2010-10-07 18:27         ` Martin Krischik
  2010-10-07 21:30           ` Adam Beneschan
  2010-10-08  0:07           ` Randy Brukardt
  0 siblings, 2 replies; 54+ messages in thread
From: Martin Krischik @ 2010-10-07 18:27 UTC (permalink / raw)


Am 07.10.2010, 13:55 Uhr, schrieb Stephen Leake  
<stephen_leake@stephe-leake.org>:

> Exactly. Suppose we have the following:
>
> type My_Type is record ... end record;
> type My_Access_Type is access all My_Type;
>
> procedure Foo_One (A : access My_Type);
>
> procedure Foo_Two (A : My_Access_Type);
>
>
> Inside Foo_Two, we know that the accessibility level of A is the same as
> the declaration of My_Access_Type,

Are you realy sure about that? My_Access_Type is an access *all* and could  
point to an aliased value on the stack.

Martin

-- 
Martin Krischik
mailto://krischik@users.sourceforge.net
https://sourceforge.net/users/krischik



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

* Re: Limited use for limited with?
  2010-10-07 18:27         ` Martin Krischik
@ 2010-10-07 21:30           ` Adam Beneschan
  2010-10-09  6:29             ` Martin Krischik
  2010-10-08  0:07           ` Randy Brukardt
  1 sibling, 1 reply; 54+ messages in thread
From: Adam Beneschan @ 2010-10-07 21:30 UTC (permalink / raw)


On Oct 7, 11:27 am, "Martin Krischik" <krisc...@users.sourceforge.net>
wrote:
> Am 07.10.2010, 13:55 Uhr, schrieb Stephen Leake  
> <stephen_le...@stephe-leake.org>:
>
> > Exactly. Suppose we have the following:
>
> > type My_Type is record ... end record;
> > type My_Access_Type is access all My_Type;
>
> > procedure Foo_One (A : access My_Type);
>
> > procedure Foo_Two (A : My_Access_Type);
>
> > Inside Foo_Two, we know that the accessibility level of A is the same as
> > the declaration of My_Access_Type,
>
> Are you realy sure about that? My_Access_Type is an access *all* and could  
> point to an aliased value on the stack.

Only if you use 'Unchecked_Access (or some other trickery).  Since
we're talking about accessibility level checks, we have to assume that
we aren't using 'Unchecked_Access, which would defeat the whole
purpose of the checks and make the discussion pointless.

                             -- Adam



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

* Re: Limited use for limited with?
  2010-10-07 18:27         ` Martin Krischik
  2010-10-07 21:30           ` Adam Beneschan
@ 2010-10-08  0:07           ` Randy Brukardt
  2010-10-09  6:21             ` Martin Krischik
  1 sibling, 1 reply; 54+ messages in thread
From: Randy Brukardt @ 2010-10-08  0:07 UTC (permalink / raw)


"Martin Krischik" <krischik@users.sourceforge.net> wrote in message 
news:op.vj7xjle3z25lew@macpro-eth1.krischik.com...
...
>> Inside Foo_Two, we know that the accessibility level of A is the same as
>> the declaration of My_Access_Type,
>
> Are you realy sure about that? My_Access_Type is an access *all* and could 
> point to an aliased value on the stack.

He is. If you try to store an access to an aliased value on the stack into 
My_Access_Type, you'll get a compile-time error that the accessibility 
fails. (Or, in a few obscure cases, Program_Error will be raised.) The rules 
that guarentee this are a constant source of headaches for the ARG and 
implementers, but Ada users don't need to worry about that.

                                      Randy.





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

* Re: Limited use for limited with?
  2010-10-05  7:35                     ` Randy Brukardt
@ 2010-10-08  8:05                       ` Maciej Sobczak
  2010-10-09  6:29                         ` Randy Brukardt
  0 siblings, 1 reply; 54+ messages in thread
From: Maciej Sobczak @ 2010-10-08  8:05 UTC (permalink / raw)


On 5 Paź, 09:35, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

> > Not at all. In my design Object knows nothing about registry. There is
> > no such dependency and therefore it does not have to be broken.
>
> But the Registries are completely unsafe! They have no way to protect
> against dangling pointers,

That's right. The problem is that none of the proposed solutions is
adequate here, for reasons that I have explained already.
My point is that this is one of those places where using plain
pointers is the best solution, even taking into account all its
potential problems.

Important note: in my design dangling pointers are prevented not by
registry or its obscure API, but by the purpose of the whole. In 100%
cases that are known to me the objects outlive the registry, so there
is no possibility to create dangling pointers. Granted, users *can*
write an artificial and nonsense code (perhaps to prove the point)
that will create dangling pointers, but no amount of protection will
prevent such intentional misuse.
Note that even now creating a dangling pointer requires explicit use
of 'Unchecked_Access. No matter what you do, you cannot protect the
user against him using Unchecked_XXX tools, which will always make all
your protections useless, no matter how sophisticated.
In short: you can protect against Murphy, but not against Machiavelli.

> It's always better to prevent abuse in the interface.

Unless the "protection" makes the system unusable. Clarity and ease of
use are important goals, too. Ironically, they even promote
correctness.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-10-05  7:25             ` Randy Brukardt
@ 2010-10-08  8:23               ` Maciej Sobczak
  2010-10-09  6:13                 ` Randy Brukardt
  0 siblings, 1 reply; 54+ messages in thread
From: Maciej Sobczak @ 2010-10-08  8:23 UTC (permalink / raw)


On 5 Paź, 09:25, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

> >No way. There are *many* Registers, meaning that a single object can
> >be registered in several registries, not just one. Will you suggest
> >passing an array of registries to the constructor? I hope not.
>
> This sounds like chaos, not a design.

Let me guess: comp.lang.ada is the only group you are registered to,
right? And of course, you are subscribed to only one mailing list,
right?

The possibility to register somewhere should be orthogonal to the
number of registries. If I was able to subscribe to comp.lang.ada, I
want to be able to subscribe to several other groups, too. It's not a
chaos, it's an obvious result of decoupling.

> >The problem with your approach is that it tries to bend the design of
> >the system in order to work around some language limitation. I prefer
> >having it the other way round.
>
> The "design" sounds more like copying bad ideas from some other
> implementation for some other programming language.

This design does not contain any elements that would be particular to
"some other programming language", or at least you have not shown it
yet.
Access values are inherent part of Ada and for example Timing Events
(D.15) are nothing else but callback registries, so I don't think I'm
doing anything extraordinary or outside of the "Ada way".

In other words, "chaos" and "bad ideas" are not appropriate words
here.

> When you start with a poor design, it's not surprising you can only find
> poor solutions...

Translation: "I don't understand the purpose of the system, but the
fact that my proposed solutions are not adequate is a sure proof that
the original design must be broken." Is that right?

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-10-08  8:23               ` Maciej Sobczak
@ 2010-10-09  6:13                 ` Randy Brukardt
  2010-10-10 14:13                   ` Maciej Sobczak
  0 siblings, 1 reply; 54+ messages in thread
From: Randy Brukardt @ 2010-10-09  6:13 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:09c36bd6-edfa-42bf-8f33-e91b0a9b0737@26g2000yqv.googlegroups.com...
On 5 Paz, 09:25, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

>> >No way. There are *many* Registers, meaning that a single object can
>> >be registered in several registries, not just one. Will you suggest
>> >passing an array of registries to the constructor? I hope not.
>>
>> This sounds like chaos, not a design.
>
>Let me guess: comp.lang.ada is the only group you are registered to, right?

Yes.

>And of course, you are subscribed to only one mailing list, right?

More than one of those.

>The possibility to register somewhere should be orthogonal to the
>number of registries. If I was able to subscribe to comp.lang.ada, I
>want to be able to subscribe to several other groups, too. It's not a
>chaos, it's an obvious result of decoupling.

But those things are registered by name (an simple text string), not 
registering an object. When you want to put something in lots of places, you 
have have an abstract way to refer to it.

Yes, you can use an access type to do that, but it is a lousy solution, 
because of dangling pointers, because it can't be stored, because there is 
no structure.

An example: in the Claw Builder, I tried to use access types to tie the 
various objects together. But it didn't work, because the structure is a 
graph of elements that are combined in various ways. There wasn't any way to 
restore the structure once it was saved to disk, saving the structure often 
saved elements multiple times, and similar problems. Moreover, the 
declarations all have to be placed in one giant package (a problem that Ada 
2005 tries to solve, but not very successfully). Eventually, I changed most 
of "links" to use names, which are then looked up in an appropriate index.

...
>> When you start with a poor design, it's not surprising you can only find
>> poor solutions...

>Translation: "I don't understand the purpose of the system, but the
>fact that my proposed solutions are not adequate is a sure proof that
>the original design must be broken." Is that right?

When I'm writing an Ada program, I want a design that can be expressed well 
in Ada. I don't much care whether it can be expressed well in some other 
language. And "well" includes safety against accidental misuse. Use of 
access types in object interfaces almost always compromises safety.

A design that can't be expressed well in Ada is a poor design (presuming you 
are planning to write the program in Ada). It would be the same for Java, 
C++, or any other programming language.

I personally think that callbacks are a poor fit for Ada (possibly because I 
started with Ada 83, where callbacks were impossible). It's not always 
possible to avoid them (i.e. GUI programming), but I don't think they should 
ever be introduced when there is an alternative. And if you do that, you 
don't need the "registration" in the first place. So I think a design using 
callbacks and registration is a "poor design". YMMV.

                                      Randy.





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

* Re: Limited use for limited with?
  2010-10-08  0:07           ` Randy Brukardt
@ 2010-10-09  6:21             ` Martin Krischik
  0 siblings, 0 replies; 54+ messages in thread
From: Martin Krischik @ 2010-10-09  6:21 UTC (permalink / raw)


Am 08.10.2010, 02:07 Uhr, schrieb Randy Brukardt <randy@rrsoftware.com>:

> "Martin Krischik" <krischik@users.sourceforge.net> wrote in message
> news:op.vj7xjle3z25lew@macpro-eth1.krischik.com...
> ...
>>> Inside Foo_Two, we know that the accessibility level of A is the same  
>>> as
>>> the declaration of My_Access_Type,
>>
>> Are you realy sure about that? My_Access_Type is an access *all* and  
>> could
>> point to an aliased value on the stack.
>
> He is. If you try to store an access to an aliased value on the stack  
> into
> My_Access_Type, you'll get a compile-time error that the accessibility
> fails. (Or, in a few obscure cases, Program_Error will be raised.) The  
> rules
> that guarentee this are a constant source of headaches for the ARG and
> implementers, but Ada users don't need to worry about that.

But if you mention Program_Error then the accessibility can not be checked  
at compile time in all circumstances. In which case an access all is not  
at all better then an anonymous access. Only a plain access will guarantee  
that accessibility can be checked statically in all circumstances.

Regards.

Martin
-- 
Martin Krischik
mailto://krischik@users.sourceforge.net
https://sourceforge.net/users/krischik



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

* Re: Limited use for limited with?
  2010-10-08  8:05                       ` Maciej Sobczak
@ 2010-10-09  6:29                         ` Randy Brukardt
  0 siblings, 0 replies; 54+ messages in thread
From: Randy Brukardt @ 2010-10-09  6:29 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:37e167dc-1741-4627-bef4-1fd8b32bdbeb@c10g2000yqh.googlegroups.com...
...
>Important note: in my design dangling pointers are prevented not by
>registry or its obscure API, but by the purpose of the whole. In 100%
>cases that are known to me the objects outlive the registry, so there
>is no possibility to create dangling pointers.

I suppose it depends upon the use. If you are the *only* person that will 
ever work on this code, and you never make mistakes, then that might in fact 
be OK.

>Granted, users *can* write an artificial and nonsense code (perhaps to 
>prove
>the point) that will create dangling pointers, but no amount of protection 
>will
>prevent such intentional misuse.

Careful: I agree that intentional misuse (such as using Unchecked_Conversion 
to avoid checks) isn't really protectable. But most misuse is accidental, 
and can even happen by someone that knows better.

It's really easy to declare an object inside of a subprogram by mistake. 
Someone (probably you) *will* do it sometime soon. Accessibility *might* 
protect you, but I've only have one single instance in my entire programming 
career where I was able to use 'Access; everywhere else I *had* to use 
'Unchecked_Access (usually because the argument was a parameter) -- so I 
wouldn't count on that to be much help.

If there are other programming using your packages, then you pretty much 
have to assume these sorts errors will happen. So what do you want to happen 
when someone accidentally misuses your code? The entire program mysteriously 
locks up? Or some sort of detection? I know which I prefer -- in Claw, we 
went to great lengths to ensure that everything will work cleanly no matter 
where someone declares a window -- in part because handling support calls 
are expensive. (And even helping programmers on your team in such cases is 
expensive.)

>> It's always better to prevent abuse in the interface.
>
>Unless the "protection" makes the system unusable. Clarity and ease of
>use are important goals, too. Ironically, they even promote
>correctness.

True, but there is nothing clear about a callback registry. It completely 
sacrifies safety (not just via dangling pointers, but also type safety) in 
order to make something easier for the programmer (the one person for whom 
"ease" is irrelevant). I think it is just a hack.

                              Randy.





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

* Re: Limited use for limited with?
  2010-10-07 21:30           ` Adam Beneschan
@ 2010-10-09  6:29             ` Martin Krischik
  2010-10-09 18:35               ` Robert A Duff
  0 siblings, 1 reply; 54+ messages in thread
From: Martin Krischik @ 2010-10-09  6:29 UTC (permalink / raw)


Am 07.10.2010, 23:30 Uhr, schrieb Adam Beneschan <adam@irvine.com>:

>  Since
> we're talking about accessibility level checks, we have to assume that
> we aren't using 'Unchecked_Access,

I thought Stephen were talking static vs. dynamic checks. He was arguing  
that anonymous access would need an dynamic check unlike a named access.  
But then he used an access all in his example - which AFAIK might needs a  
dynamic check as well. I would argue that if you use an access all you can  
just as well use an anonymous access. And I feel that many Ada programmes  
these day type »access all« out of habit without thinking of the  
implications.

Regards

Martin

-- 
Martin Krischik
mailto://krischik@users.sourceforge.net
https://sourceforge.net/users/krischik



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

* Re: Limited use for limited with?
  2010-10-09  6:29             ` Martin Krischik
@ 2010-10-09 18:35               ` Robert A Duff
  0 siblings, 0 replies; 54+ messages in thread
From: Robert A Duff @ 2010-10-09 18:35 UTC (permalink / raw)


"Martin Krischik" <krischik@users.sourceforge.net> writes:

> But then he used an access all in his example - which AFAIK might needs
> a  dynamic check as well.

All accessibility checks on named access types with "all"
are done at compile time.  According to the RM, they are
done at run time in some generic-related cases, but most
compilers (the ones that do macro-expanded generics)
will check those at compile time, too (and give a warning).

Only anonymous access types have run-time accessibility
checking (which I think was a mistake, by the way).

But if you use 'Unchecked_Access, you will defeat both the
compile-time and the run-time checks.

- Bob



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

* Re: Limited use for limited with?
  2010-10-09  6:13                 ` Randy Brukardt
@ 2010-10-10 14:13                   ` Maciej Sobczak
  2010-10-11  6:23                     ` Randy Brukardt
  0 siblings, 1 reply; 54+ messages in thread
From: Maciej Sobczak @ 2010-10-10 14:13 UTC (permalink / raw)


On 9 Paź, 08:13, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

> Eventually, I changed most
> of "links" to use names, which are then looked up in an appropriate index.

And what's in the index? The index becomes a registry with the same
problems, just moved elsewhere. There are three options:

1. index/registry contains the actual objects - this has a big impact
on how the objects are created; this might impose limitations that
users will not want to accept
2. index/registry contains deep copies of the actual objects - then,
the updates will not be propagated
3. index/registry contains access values to actual objects - then,
beware dangling pointers
3a. objects know how to remove themselves from the index/registry -
this has a big impact on how the objects are destroyed and on how the
type is defined (forget interfaces); this in turn might impose
limitations that users will not want to accept, either

?

> A design that can't be expressed well in Ada is a poor design

So let's be constructive. The problem is the following:

- there is some activity happening in the environment that generates
stimulation that should be handled by the program
- there is some common interface for the propagation of this
stimulation
- users want to implement their handling routines

In short (hey, that's a candidate for a design pattern): Event
Handler.

Ada provides nice solution for interrupts, but not all such scenarios
are related to interrupts. Think about HTTP requests (AWS), RPC
invocations (PolyORB), alarm notifications, and so on - in many cases
all such things are delivered over the network, but this is not
necessary.

How would you express such a pattern in Ada? I still don't see a
plausible solution and declaring the one that is simplest, most
readable, and most flexible for the final user to be not "the Ada way"
is not constructive, either.

> I personally think that callbacks are a poor fit for Ada

So how to solve the above problem in Ada properly?

Or should we say that Ada is a poor fit for this class of problems
instead?

> It's not always
> possible to avoid them (i.e. GUI programming), but I don't think they should
> ever be introduced when there is an alternative.

So what is the alternative? Please do not repeat the ones that were
already dismissed.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-10-10 14:13                   ` Maciej Sobczak
@ 2010-10-11  6:23                     ` Randy Brukardt
  2010-10-12 19:29                       ` Maciej Sobczak
  0 siblings, 1 reply; 54+ messages in thread
From: Randy Brukardt @ 2010-10-11  6:23 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:c76f3559-7c89-4536-b92f-951da5a44170@m1g2000vbh.googlegroups.com...
On 9 Paz, 08:13, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

>> Eventually, I changed most
>> of "links" to use names, which are then looked up in an appropriate 
>> index.
>
>And what's in the index? The index becomes a registry with the same
>problems, just moved elsewhere.

Well, I'd call it a database, not a "registry".

> There are three options:
>
>1. index/registry contains the actual objects - this has a big impact
>on how the objects are created; this might impose limitations that
>users will not want to accept

Clients of your abstraction have to live with whatever restrictions you (the 
abstraction author) imposes. Or they have to find a different abstraction. 
In our case, we did this, because we needed the capability to make the 
object database persistent. That can't be usefully done with access types 
(at least not when you have a web of interconnecting links). The clients of 
the abstraction had to live within the limitations; else the users of the 
end program would have been very unhappy (Save or Open wouldn't work).

>2. index/registry contains deep copies of the actual objects - then,
>the updates will not be propagated

I don't think this is a real choice.

>3. index/registry contains access values to actual objects - then,
>beware dangling pointers
>3a. objects know how to remove themselves from the index/registry -
>this has a big impact on how the objects are destroyed and on how the
>type is defined (forget interfaces); this in turn might impose
>limitations that users will not want to accept, either

IMHO, Interfaces are worthless. For me, only implementation inheritance is 
worth bothering with, and you can't do that with interfaces. The contortions 
that we've gone through trying to use them for the queue containers pretty 
much have proved the point to me. But YMMV.

After all, the implementation of controlled types in Janus/Ada is exactly 
this model: each object "knows" how to finalize itself, and the "registry" 
determines when the object needs to be finalized. There cannot be any 
dangling pointers (at least not from this mechanism, other program bugs can 
damage the links that register the objects and cause bugs that are nearly 
impossible to debug).

To use this model, the only issue is that you have to derive all of your 
types from a "Registerable" type. That wouldn't be a big deal, unless you 
need to add this property to the middle of an existing derivation tree. Ada 
doesn't have sane way to do that (mixin generics can work, but are horrible 
to write and horrible to use).

> ?

>> A design that can't be expressed well in Ada is a poor design
>
>So let's be constructive. The problem is the following:
>
>- there is some activity happening in the environment that generates
>stimulation that should be handled by the program
>- there is some common interface for the propagation of this
>stimulation

I don't believe this is true often enough in practice to be a reasonable 
stipulation.

>- users want to implement their handling routines

> In short (hey, that's a candidate for a design pattern): Event Handler.

>Ada provides nice solution for interrupts, but not all such scenarios
>are related to interrupts. Think about HTTP requests (AWS), RPC
>invocations (PolyORB), alarm notifications, and so on - in many cases
>all such things are delivered over the network, but this is not
>necessary.

Generally, such notifications include data. So you have to deliver the data 
somehow. If you use a single interface, you break type safety with accessing 
the data (at best, you have some sort of runtime check which adds to your 
testing load).

In every instance where I've had to do some sort of event handling, I've 
written a separate specification for each handler. And a separate way of 
invoking (since generally the notications come from some non-Ada mechanism: 
TCP/IP, or a Windows Message, or an interrupt, etc.; and each of these 
things triggers an event in a different way).

>How would you express such a pattern in Ada? I still don't see a
>plausible solution and declaring the one that is simplest, most
>readable, and most flexible for the final user to be not "the Ada way"
>is not constructive, either.

You have already decided on a solution, and are trying to shoehorn that into 
Ada. But you are losing safety: both type safety and program safety (because 
of the dangling pointer issues) by doing so. Every solution has tradeoffs, 
and you are picking the one that has the worst attributes from an Ada 
perspective for the purpose of making programming easier by the "final user" 
(really a programmer, and not really final; my mother is a "final user" and 
I'm certain she's not creating event handlers :-).

[Note: I usually reserve "user" for the person who uses the program created 
by the programmer, and use "programmer" or "client" when talking about the 
person who uses a library package or other Ada code. That's very important 
when talking about something like Claw, where the user of Claw and the user 
of the program created by the use of Claw are very different people -- and 
the needs of both have to be considered.]

>> I personally think that callbacks are a poor fit for Ada

>So how to solve the above problem in Ada properly?
>
>Or should we say that Ada is a poor fit for this class of problems
>instead?

Ada is a poor fit for the "Event Handler" as you described it, but I believe 
that pattern is likely to be a bad choice in most instances.

>> It's not always
>> possible to avoid them (i.e. GUI programming), but I don't think they 
>> should
>> ever be introduced when there is an alternative.
>
>So what is the alternative? Please do not repeat the ones that were
>already dismissed.

Well, if you're not going to consider the solutions, it's probably not worth 
discussing further.

I don't believe that there is any general pattern that makes sense (for Ada 
or any other language for that matter); it depends on the use of the events, 
the data that needs to be carried along, and other issues.

For instance, for Claw, we used OOP dispatching to deliver events. This 
didn't require any Ada registration because Windows (and all other GUIs I've 
looked at) include a window handle in the event message; from the window 
handle you can get the associated Ada object (it's stored within Windows 
when the window is created), and then we make the appropriate dispatching 
call. The majority of the handlers have separate interfaces with custom 
parameter lists so that strong typing prevents mistakes in the use of the 
data. OOP IS harder for the programmers to use (Ada requires a lot of typing 
to overriding routines), and harder for the author as well, but is better 
than raw callbacks as it is impossible to "register" the wrong kind of 
object to get a callback. (Doing that is one of the hardest bugs to figure 
out, as your object just doesn't get its event.)

In a few cases in Claw we used an OOP data block with a number of extensions 
(so we could send different data types to a single handler, by declaring 
appropriate extensions). This worked but is not very satisfactory, because 
any mistakes cannot be caught until runtime. That causes them to get past 
testing.

We've already talked about the Claw Builder; I don't have much to add about 
that.

Janus/Ada doesn't use any events.

In the Web Server and Spam Filter, the events come from TCP/IP. In this 
case, we don't want a callback per-se because we want to treat each event as 
a "job", and schedule each "job" to be run by one of a pool of tasks. The 
tasks are generally declared by one or more task types; I've always used 
dedicated task types for particular kinds of jobs (for instance, receiving, 
filtering, and sending e-mail is done by different sets of tasks). The 
primary purpose of this is to ensure that a single expensive request doesn't 
prevent other requests from being processed. This reduces the chance of a 
denial-of-service problem.

I guess my point is that you need different patterns for handling "events" 
depending upon whether you need tasking, whether OOP is acceptable, and so 
on. I don't think that there is a general pattern that is acceptable. I also 
think that any pattern that you use has to tie the events and objects 
together, else you've lost any hope of compile-time type safety and quite 
possibly made the system much harder to test.

                                      Randy.







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

* Re: Limited use for limited with?
  2010-10-11  6:23                     ` Randy Brukardt
@ 2010-10-12 19:29                       ` Maciej Sobczak
  2010-10-12 20:19                         ` Dmitry A. Kazakov
  2010-10-13  2:09                         ` Randy Brukardt
  0 siblings, 2 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-10-12 19:29 UTC (permalink / raw)


On 11 Paź, 08:23, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

> > There are three options:
>
> >1. index/registry contains the actual objects - this has a big impact
> >on how the objects are created; this might impose limitations that
> >users will not want to accept

> In our case, we did this, because we needed the capability to make the
> object database persistent.

This is not my goal and there is no such requirement in my system, so
I don't consider it a reason for not using access types.

> >3. index/registry contains access values to actual objects

> IMHO, Interfaces are worthless.

I hope you understand that this is a very strong statement. It
basically stands in direct opposition to the work that has been done
to introduce them into the language.

> The contortions
> that we've gone through trying to use them for the queue containers

There is no obligation to use them where they are not adequate.
However, this says absolutely nothing about their use in those places
where they *are* useful.

> >So let's be constructive. The problem is the following:
>
> >- there is some activity happening in the environment that generates
> >stimulation that should be handled by the program
> >- there is some common interface for the propagation of this
> >stimulation
>
> I don't believe this is true often enough in practice to be a reasonable
> stipulation.

Let's leave this requirement out of the picture. In fact, this is not
a requirement at all, but since Ada is a strongly-typed language,
there *must* be some specification of the protocol to pass the event
between program modules.

> >- users want to implement their handling routines
> > In short (hey, that's a candidate for a design pattern): Event Handler.

> Generally, such notifications include data.

Typically, yes.

> So you have to deliver the data
> somehow.

Typically, the data will be passed as a parameter of the dispatching
operation that defines the protocol.

> If you use a single interface, you break type safety with accessing
> the data

No, not at all. The type safety is not compromised in any way.
Consider:

   procedure Handle_Event (H : Handler_Access; Data : in Integer);

(where type Handler_Access is access all Handler'Class)

In what way is the type safety of Data compromised here?

> In every instance where I've had to do some sort of event handling, I've
> written a separate specification for each handler.

That's OK. These are defined as interfaces in my system.

> You have already decided on a solution, and are trying to shoehorn that into
> Ada.

No. I have reviewed the available language features and I have chosen
the one that allows me to solve the problem in the best way.
You still have not proven it otherwise. :-)

> But you are losing safety: both type safety and program safety (because
> of the dangling pointer issues) by doing so.

Type safety is not compromised. All operations are strongly types.
Some of them might be lately bound (dispatching), but all are strongly
typed. If you think otherwise, please explain.
Program safety is not compromised due to the fact that all reasonable
use cases guarantee that handlers outlive the registries.

> Every solution has tradeoffs,
> and you are picking the one that has the worst attributes from an Ada
> perspective

I'm still waiting for you to show it. And I still don't see it.

> For instance, for Claw, we used OOP dispatching to deliver events. This
> didn't require any Ada registration because Windows (and all other GUIs I've
> looked at) include a window handle in the event message;

GUI has the property that data sources and receivers are (typically)
bound in the 1:1 way. This allowed you to cheat a bit by piggy-backing
the object reference in the window handle.
This is not applicable in general.

> In the Web Server and Spam Filter, the events come from TCP/IP. In this
> case, we don't want a callback per-se because we want to treat each event as
> a "job", and schedule each "job" to be run by one of a pool of tasks.

Yes, this is a possible approach, but tasks and jobs are bound in the
1:N way (that is, each job is delivered to exactly one task). Basic
multitasking patterns involving queues or other buffers are OK for
this.
But it is not applicable in general. Think about how messed up it
would become for N:M case (each job delivered to potentially many
tasks).

It is true that in my system it *would* be possible to do this, but I
have chosen not to do it in order to avoid forcing the user (client
for you) to create additional tasks on his side. It is perfectly
possible to run the whole system in a single-tasking environment -
that is, the one that does not even support multiple tasks. Since my
system is targeted at embedded installations (among others), I
consider this to be an important feature. The user/client can always
add tasking if needed.

> I don't think that there is a general pattern that is acceptable.

I agree. But we are now discussing something different: you seem to
state that *some* pattern is *universally UNacceptable*, no matter
what - and this is something I don't agree with.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-10-12 19:29                       ` Maciej Sobczak
@ 2010-10-12 20:19                         ` Dmitry A. Kazakov
  2010-10-13  2:09                         ` Randy Brukardt
  1 sibling, 0 replies; 54+ messages in thread
From: Dmitry A. Kazakov @ 2010-10-12 20:19 UTC (permalink / raw)


On Tue, 12 Oct 2010 12:29:28 -0700 (PDT), Maciej Sobczak wrote:

> On 11 Paďż˝, 08:23, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> 
>> IMHO, Interfaces are worthless.
> 
> I hope you understand that this is a very strong statement. It
> basically stands in direct opposition to the work that has been done
> to introduce them into the language.

How could it be otherwise if that work damaged Ada?

I am pleasantly surprised that a prominent ARG member considers interfaces
[at least] worthless. It is a progress, I would say. 

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



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

* Re: Limited use for limited with?
  2010-10-12 19:29                       ` Maciej Sobczak
  2010-10-12 20:19                         ` Dmitry A. Kazakov
@ 2010-10-13  2:09                         ` Randy Brukardt
  2010-10-13  8:44                           ` Georg Bauhaus
  2010-10-13  9:43                           ` Maciej Sobczak
  1 sibling, 2 replies; 54+ messages in thread
From: Randy Brukardt @ 2010-10-13  2:09 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:1f38791b-a579-49ed-839c-e6ff3867de76@30g2000yqm.googlegroups.com...
On 11 Paz, 08:23, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
>> > There are three options:
>>
>> >1. index/registry contains the actual objects - this has a big impact
>> >on how the objects are created; this might impose limitations that
>> >users will not want to accept
>
>> In our case, we did this, because we needed the capability to make the
>> object database persistent.
>
>This is not my goal and there is no such requirement in my system, so
>I don't consider it a reason for not using access types.

Persistence is a very common requirement, so for general facilities it *is* 
a reason to avoid access types.

...
>> IMHO, Interfaces are worthless.
>
>I hope you understand that this is a very strong statement. It
>basically stands in direct opposition to the work that has been done
>to introduce them into the language.

I DID a lot of that work. It isn't the only work that I've done on the 
language that I didn't think was worthwhile (don't get me started on 
coextensions). But there are a lot of people that would disagree with me on 
interfaces; we added it for them, not for me!

In every instance that I have ever wanted to use an abstract type, I have 
wanted to provide some data and or default implementations with that 
abstract type. The classic example is controlled types (where the private 
data of the root types provide the links used to manage the finalization), 
but that has happened in several places in Claw as well. Having to implement 
the same operation in the same way in almost every extension of an interface 
is not likely to add anything to maintainability nor to readability. So what 
"ility" is it adding??

Classwide routines are great for doing operations that are always handled 
the same way. But if the operation is *usually* done one way but in some 
circumstances needs to be done differently, overriding is needed and the 
inability to have concrete operations requires lots of manual repetition.

In addition, hardly anything is common enough to really benefit from 
interfaces. Every hierarchy that I have dealt with is very shallow, with 
only a handful of levels of derivation. There isn't that many operations 
that are shared between object types.

>> The contortions
>> that we've gone through trying to use them for the queue containers
>
>There is no obligation to use them where they are not adequate.
>However, this says absolutely nothing about their use in those places
>where they *are* useful.

The queue containers are about the most useful item that I could actually 
imagine for interfaces. This is a case with multiple plasible 
implementations and a well-defined set of operations that work with each 
implementation unmodified. If it doesn't work well on the queues, I'm 
skeptical that it can work well anywhere.

...
>> If you use a single interface, you break type safety with accessing
>> the data
>
>No, not at all. The type safety is not compromised in any way.
>Consider:
>
>   procedure Handle_Event (H : Handler_Access; Data : in Integer);
>
>(where type Handler_Access is access all Handler'Class)
>
>In what way is the type safety of Data compromised here?

It's not. But it is highly unlikely that different events need the same 
data. So you have to have separate event handlers for each event. Once you 
have done that, there no longer is a common mechanism for 
registering/triggering events -- you have to recode it separately for each 
event. If that's the case, the concerns about coupling are pretty much 
eliminated, as both the object and the event have to know about each other 
anyway.

>> In every instance where I've had to do some sort of event handling, I've
>> written a separate specification for each handler.
>
>That's OK. These are defined as interfaces in my system.

And how does this help? You can't make a call to some routine with an 
unknown parameter list, just because it is defined in an interface. So you 
still end up with a separate call to each handler, and all the interface has 
bought you is additional complication and lots of runtime overhead.

...
>> But you are losing safety: both type safety and program safety (because
>> of the dangling pointer issues) by doing so.
>
>Type safety is not compromised. All operations are strongly types.
>Some of them might be lately bound (dispatching), but all are strongly
>typed. If you think otherwise, please explain.

You and I must be thinking of different solutions, because I can't see any 
way for that to work with a single handler registry type. And if you have 
multiple such types, I don't see why you'd want to introduce the 
complication: just deliver the events directly to the appropriate objects.

>Program safety is not compromised due to the fact that all reasonable
>use cases guarantee that handlers outlive the registries.

Again, you are saying that no one that will program your system will make a 
mistake. It must be nice to have such perfect programmers -- I'd like to 
meet one someday. ;-)

Work on the Ada standard and on Ada compilers has repeately reminded me that 
even if some use is an obvious pathology, it is pretty common that someone 
will try to use it. And it's not unusual that they've found a plasible use 
for it. (Programmers as a group are more clever than language designers or 
compiler writers, even if the latter individuals are brilliant.) So I always 
want to prevent misuse up-front, by the design if possible or by 
compile-time rules checks.

>> Every solution has tradeoffs,
>> and you are picking the one that has the worst attributes from an Ada
>> perspective
>
>I'm still waiting for you to show it. And I still don't see it.

Ada is all about tasking and about nested items. You are adopting a solution 
that will work poorly for both. And I've show the problems repeatedly. You 
don't believe they are problems because you are certain that no one will 
every try to use your code differently that you intended. In the unlikely 
case that you are right, I agree with you: any old design will work well --  
use any spaggetti code that you want and it would *still* work. But I don't 
think you are being realistic: for instance, I want to avoid allocating 
objects when possible, because there are a lot less memory leaks when you 
let the compiler do the cleanup. So I declare a lot of objects in 
subprograms and in blocks. That doesn't mean that I wouldn't need one of 
them to handle an event!

Anyway, I think we have to agree to disagree on this one, because we don't 
even have the same worldview.

...
>> In the Web Server and Spam Filter, the events come from TCP/IP. In this
>> case, we don't want a callback per-se because we want to treat each event 
>> as
>> a "job", and schedule each "job" to be run by one of a pool of tasks.
>
>Yes, this is a possible approach, but tasks and jobs are bound in the
>1:N way (that is, each job is delivered to exactly one task). Basic
>multitasking patterns involving queues or other buffers are OK for this.
>
>But it is not applicable in general. Think about how messed up it
>would become for N:M case (each job delivered to potentially many
>tasks).

N:M would be what I called chaos at the start of this thread! There has to 
be some structure to the events or you really do have chaos. So you have to 
partition that into a set of events that all go to a single object/task, and 
broadcast events that each go to a set of objects/tasks. That is, the 
program is a bunch of 1:N and N:1 events, and they don't (directly) 
interact.

>It is true that in my system it *would* be possible to do this, but I
>have chosen not to do it in order to avoid forcing the user (client
>for you) to create additional tasks on his side. It is perfectly
>possible to run the whole system in a single-tasking environment -
>that is, the one that does not even support multiple tasks. Since my
>system is targeted at embedded installations (among others), I
>consider this to be an important feature. The user/client can always
>add tasking if needed.

It's too late at that point, as you now have a single event handler task as 
a bottleneck. If you need tasks, you have to add them early to get even a 
semblance of parallel execution.

Even so, I understand your concern. Not all systems can use tasking 
effectively (although this is something that is changing rapidly, multicore 
chips are becoming the norm). I think it is necessary to use different 
patterns in the two cases ("jobs" vs. "events"), and I don't think it is a 
good idea to try to unify them.

>> I don't think that there is a general pattern that is acceptable.
>
>I agree. But we are now discussing something different: you seem to
>state that *some* pattern is *universally UNacceptable*, no matter
>what - and this is something I don't agree with.

There is nothing that is ever that black-and-white. This is a pattern that I 
think is best avoided if possible. But it clearly isn't always possible to 
avoid it. Registration is, for instance, the best way to build an object 
factory in Ada. But it is interesting that you're usually not storing 
pointers into the registration map in that case.

                                            Randy.





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

* Re: Limited use for limited with?
  2010-10-13  2:09                         ` Randy Brukardt
@ 2010-10-13  8:44                           ` Georg Bauhaus
  2010-10-15  0:59                             ` Randy Brukardt
  2010-10-13  9:43                           ` Maciej Sobczak
  1 sibling, 1 reply; 54+ messages in thread
From: Georg Bauhaus @ 2010-10-13  8:44 UTC (permalink / raw)


On 10/13/10 4:09 AM, Randy Brukardt wrote:
> "Maciej Sobczak"<see.my.homepage@gmail.com>  wrote in message

>> But it is not applicable in general. Think about how messed up it
>> would become for N:M case (each job delivered to potentially many
>> tasks).
>
> N:M would be what I called chaos at the start of this thread! There has to
> be some structure to the events or you really do have chaos. So you have to
> partition that into a set of events that all go to a single object/task, and
> broadcast events that each go to a set of objects/tasks. That is, the
> program is a bunch of 1:N and N:1 events, and they don't (directly)
> interact.

The design seems to assume one program of unchanging
object structure once it has been output by the compiler.
After that, it is known to be organized such and such, known
to the one instance of program integration. Some organizational
unit is aware of its total design.

Assume instead a program composed of parts such that
organizational boundaries will prevent knowing the total
design, in every detail. For example, it is not known what exactly
N and M will be (for N:M or even N:1).

The system has a changing number of superior objects (agents,
triggering events) and inferior objects (handling events).

Software companies write components, other software companies
compose programs from the components. Engineers add and remove
components, during system operation if possible. But no one
knows beforehand the set of events, or the set of handlers.

Typical Superiors might be called The_Mechanical_Seargant, Task_Queue,
Central_Services, Boss_Miller, The_President, Radar, or Klaxon.

Inferiors are identified by Worker, Mr_Hill, Valve, Sink,
or Magic_Apparatus.

There may one or many of each of those, their number can change,
and they may be turned on or off. That is N(t):M(t), t in Time.

For example, Worker(13) might be busy and thus is unavailable
for handing any event.

Boss_Miller might be off. The_President might visit the site
and trigger an unforeseen event, no matter what.

Broadcast then really means broadcast: just any event handler
can pick an event and react as programmed. Or not. But the programmers
who wrote the handlers had not known about the totality
(there you have another "ility"  ;-)
of circumstances of events, or their origin, or their specific
type.  Neither did the system makers foresee all circumstances
triggering an event, or handlers available.
Neither party may be able to predict all additions of events or
handlers to some partition, or their removal, or malfunctioning.

Is it realistic to assume that such a large, multi-organization,
changing system can be modeled with "known specific handler"
in mind?  Without pointers, but scope based?

(And isn't something like Linda tuple spaces, IIRC, directly
opposed to scope based and deterministic solutions?)


Georg



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

* Re: Limited use for limited with?
  2010-10-13  2:09                         ` Randy Brukardt
  2010-10-13  8:44                           ` Georg Bauhaus
@ 2010-10-13  9:43                           ` Maciej Sobczak
  1 sibling, 0 replies; 54+ messages in thread
From: Maciej Sobczak @ 2010-10-13  9:43 UTC (permalink / raw)


On 13 Paź, 04:09, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

> >> IMHO, Interfaces are worthless.
>
> >I hope you understand that this is a very strong statement. It
> >basically stands in direct opposition to the work that has been done
> >to introduce them into the language.
>
> I DID a lot of that work. [...]
> we added it for them, not for me!

This shows that there are very interesting forces in action in ARG.
While we're at it, I believe that real multiple inheritance would be
much better solution, but I accept interfaces as something that is
still useful. Not having both of them would be very limiting.

> >No, not at all. The type safety is not compromised in any way.
> >Consider:
>
> >   procedure Handle_Event (H : Handler_Access; Data : in Integer);
>
> >(where type Handler_Access is access all Handler'Class)
>
> >In what way is the type safety of Data compromised here?
>
> It's not. But it is highly unlikely that different events need the same
> data. So you have to have separate event handlers for each event. Once you
> have done that, there no longer is a common mechanism for
> registering/triggering events -- you have to recode it separately for each
> event.

Yes.

> If that's the case, the concerns about coupling are pretty much
> eliminated, as both the object and the event have to know about each other
> anyway.

The decoupling allows to have N similar event sources and M similar
event handlers. I find it frequently the case in control or monitoring
systems, where many measurement systems produce data that can be
processed or displayed by many clients. The decoupling is needed here
so that data sources don't have to *statically* know their receivers.
The "wiring" of the whole is driven by configuration, which is loaded
at run-time.

Georg already described the pattern in more detail, so I will not
repeat it.

> You and I must be thinking of different solutions, because I can't see any
> way for that to work with a single handler registry type. And if you have
> multiple such types, I don't see why you'd want to introduce the
> complication: just deliver the events directly to the appropriate objects.

And here's the catch: event sources don't know their receivers until
the program is run[*], so they cannot deliver the events *directly* to
appropropriate objects. Some level of indirection is needed here and
access values provide the required capability with very little
(negligible) overhead. I think that this is the detail that we have
missed in the discussion up to now.

[*] Actually, the wiring of the components is not necessarily done at
run-time, but certainly later than the event producer is compiled. In
other words, the event producer is compiled as a module and delivered
to the client that adds his handlers. There is no way for the producer
to deliver events *directly* to handlers, as handlers are not known a
priori. And generics are too complex to handle that cleanly.

> >Program safety is not compromised due to the fact that all reasonable
> >use cases guarantee that handlers outlive the registries.
>
> Again, you are saying that no one that will program your system will make a
> mistake.

I'm saying that they will make a lot less mistakes when given a clear
and readable API. The strategy seems to be working so far.

> But I don't
> think you are being realistic: for instance, I want to avoid allocating
> objects when possible, because there are a lot less memory leaks

Again: handlers are not allocated dynamically, they are typically
static entities. Their associations with registries can be dynamic,
though, but there is no danger in it.

> Anyway, I think we have to agree to disagree on this one, because we don't
> even have the same worldview.

I think so.

--
Maciej Sobczak * http://www.inspirel.com



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

* Re: Limited use for limited with?
  2010-10-13  8:44                           ` Georg Bauhaus
@ 2010-10-15  0:59                             ` Randy Brukardt
  0 siblings, 0 replies; 54+ messages in thread
From: Randy Brukardt @ 2010-10-15  0:59 UTC (permalink / raw)


"Georg Bauhaus" <rm-host.bauhaus@maps.futureapps.de> wrote in message 
news:4cb57156$0$7654$9b4e6d93@newsspool1.arcor-online.net...
> On 10/13/10 4:09 AM, Randy Brukardt wrote:
...
> Is it realistic to assume that such a large, multi-organization,
> changing system can be modeled with "known specific handler"
> in mind?  Without pointers, but scope based?

Ada would be a lousy choice for such a system. Most of Ada's advantages are 
predicated on compile-time checking of correctness, and that is impossible 
by definition for a dynamically changing system without a defined structure.

You could use Ada if you have very strong interfaces (and I don't mean 
interfaces the language feature but simply the totality of the type 
definitions, subprogram profiles and the like) for the plug-ins. But that 
still requires a lot more organization than you are postulating here.

I wouldn't argue that there are such systems -- any widely-used OS would be 
similar. (Although even there the interfaces and interactions could be much 
better defined than in your thought experiment). Just because they exist 
doesn't mean that Ada is well-suited to program them.

                                Randy.







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

end of thread, other threads:[~2010-10-15  0:59 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-28  7:37 Limited use for limited with? Maciej Sobczak
2010-09-28  9:04 ` Alex R. Mosteo
2010-09-30  7:24   ` Stephen Leake
2010-09-30  9:21     ` Alex R. Mosteo
2010-09-28  9:18 ` Ludovic Brenta
2010-09-28 12:59   ` Maciej Sobczak
2010-09-28 13:45     ` Dmitry A. Kazakov
2010-09-28 21:57       ` Maciej Sobczak
2010-09-29  6:03         ` Ludovic Brenta
2010-09-29  8:25           ` Maciej Sobczak
2010-09-29  7:51         ` Dmitry A. Kazakov
2010-09-29  8:38           ` Maciej Sobczak
2010-09-29  9:16             ` Dmitry A. Kazakov
2010-09-29 12:22               ` Maciej Sobczak
2010-09-29 13:41                 ` Dmitry A. Kazakov
2010-09-29 15:07                   ` Georg Bauhaus
2010-09-29 19:22                     ` Dmitry A. Kazakov
2010-09-29 20:51                   ` Maciej Sobczak
2010-09-29 21:18                     ` Dmitry A. Kazakov
2010-10-05  7:35                     ` Randy Brukardt
2010-10-08  8:05                       ` Maciej Sobczak
2010-10-09  6:29                         ` Randy Brukardt
2010-10-05  7:25             ` Randy Brukardt
2010-10-08  8:23               ` Maciej Sobczak
2010-10-09  6:13                 ` Randy Brukardt
2010-10-10 14:13                   ` Maciej Sobczak
2010-10-11  6:23                     ` Randy Brukardt
2010-10-12 19:29                       ` Maciej Sobczak
2010-10-12 20:19                         ` Dmitry A. Kazakov
2010-10-13  2:09                         ` Randy Brukardt
2010-10-13  8:44                           ` Georg Bauhaus
2010-10-15  0:59                             ` Randy Brukardt
2010-10-13  9:43                           ` Maciej Sobczak
2010-09-28 15:15     ` Ludovic Brenta
2010-09-28 22:04       ` Maciej Sobczak
2010-09-28 15:54   ` Robert A Duff
2010-09-30  7:27   ` Stephen Leake
2010-09-30  7:33     ` Ludovic Brenta
2010-09-30 16:03     ` Adam Beneschan
2010-10-07 11:55       ` Stephen Leake
2010-10-07 18:27         ` Martin Krischik
2010-10-07 21:30           ` Adam Beneschan
2010-10-09  6:29             ` Martin Krischik
2010-10-09 18:35               ` Robert A Duff
2010-10-08  0:07           ` Randy Brukardt
2010-10-09  6:21             ` Martin Krischik
2010-09-28  9:32 ` Vadim Godunko
2010-09-28 11:34 ` stefan-lucks
2010-09-28 13:15   ` stefan-lucks
2010-09-28 16:55 ` Adam Beneschan
2010-09-28 17:31   ` Robert A Duff
2010-09-28 19:24     ` Adam Beneschan
2010-09-28 20:32       ` Vadim Godunko
2010-09-28 21:32         ` Adam Beneschan

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