comp.lang.ada
 help / color / mirror / Atom feed
* Run-time accessibility checks (was: Construction initialization problem)
@ 2008-12-06 10:15 Dmitry A. Kazakov
  2008-12-06 17:10 ` Ludovic Brenta
  2008-12-11  0:55 ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
  0 siblings, 2 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-06 10:15 UTC (permalink / raw)


On Fri, 5 Dec 2008 19:42:40 -0600, Randy Brukardt wrote:

"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:d16z537mbee4$.wp9rmx0b7kjf.dlg@40tude.net...

>> The language problem is lack of abstraction. If there were abstract access
>> types, then you could make an instance of A implement the interface of
>> "access A" and them simply put an object of A as a discriminant for B:
>>
>>   type AA is new A and access A with null record; -- A and access to A
>>   overriding function "'Access" (X : A) return access A;
>>   function Create return AA; -- Creates an instance of AA
>>   B_with_A : B (Create); -- Constrain it by an object
> 
> I don't understand this point at all. But it doesn't matter, because a 
> function like your function "access" doesn't work: the accessibility will be 
> wrong.

Know what, nobody cares. The bad thing is that programmers used to use
Unchecked_Access everywhere. The idea of accessibility checks was good, but
its implementation in Ada was a flop.

It would be interesting to make a poll, how many programmers

1. start straight with Unchecked_Access

2. write Access first and then switch to Unchecked_Access after the first
compiler message without analyzing the message

3. try to understand the message and change the design

My guess is 65-30-5. Yours?

> I've been trying to work on this problem, but the obvious solutions would 
> require full dynamic accessibility checks, including passing the 
> accessibility of all by-reference parameters -- and that is way too 
> expensive to consider. Plus dynamic checks provide a new failure mechanism 
> for code; it's not clear that is an advantage.

Ooch, this is the major contributor to the group 1. If I had any danger
that X'Access might fail at run-time, I would immediately switch to
X'Unchecked_Access. It is absolutely unacceptable to me that a correct
program might fail at run-time because of accessibility checks. The only
case I could buy it, if exceptions where contracted, so that I would get an
compile-time error at some other place. Like "Constraint_Error may be
propagated, but the contract states otherwise."
 
> I think that I might be able to fix the problem in the context of the 
> containers only, and for dereference of the objects only, but it is not 
> clear that the fix is worth the effort.

It certainly does not. IMO Ada needs "setters" with the syntax sugar of an
assignment, it does not need outward access types. The whole idea is just
not Ada.

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



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

* Re: Run-time accessibility checks (was: Construction initialization problem)
  2008-12-06 10:15 Run-time accessibility checks (was: Construction initialization problem) Dmitry A. Kazakov
@ 2008-12-06 17:10 ` Ludovic Brenta
  2008-12-07  8:44   ` Run-time accessibility checks Dmitry A. Kazakov
  2008-12-11  0:55 ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Ludovic Brenta @ 2008-12-06 17:10 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> It would be interesting to make a poll, how many programmers
>
> 1. start straight with Unchecked_Access
>
> 2. write Access first and then switch to Unchecked_Access after the first
> compiler message without analyzing the message
>
> 3. try to understand the message and change the design

Put me in category 3. However, changing the design isn't always
desirable because alternative designs may have unacceptable drawbacks.

> My guess is 65-30-5. Yours?

I don't know but I don't remember seeing any Unchecked_Access that
wasn't thoroughly explained in the comments near it; this would
indicate the person who wrote it was at least in category 2.

> > I've been trying to work on this problem, but the obvious solutions would
> > require full dynamic accessibility checks, including passing the
> > accessibility of all by-reference parameters -- and that is way too
> > expensive to consider. Plus dynamic checks provide a new failure mechanism
> > for code; it's not clear that is an advantage.
>
> Ooch, this is the major contributor to the group 1. If I had any danger
> that X'Access might fail at run-time, I would immediately switch to
> X'Unchecked_Access.

Actually, the presence of run-time accessibility checks are the reason
that puts me in category 3. If the run-time overhead or, worse, the
possibility of failure at run-time are unacceptable, then I prefer not
to use access types at all.

> It is absolutely unacceptable to me that a correct
> program might fail at run-time because of accessibility checks.

I differ here; to me, a program that fails an accessibility check at
run time is incorrect.

> The only
> case I could buy it, if exceptions where contracted, so that I would get an
> compile-time error at some other place. Like "Constraint_Error may be
> propagated, but the contract states otherwise."

In my understanding, there is an implicit contract stating that all
subprograms may raise at least Program_Error, Storage_Error or
Constraint_Error. I accept that as a fact and keep it in mind when
designing.

--
Ludovic Brenta.



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

* Re: Run-time accessibility checks
  2008-12-06 17:10 ` Ludovic Brenta
@ 2008-12-07  8:44   ` Dmitry A. Kazakov
  2008-12-07 14:56     ` Ludovic Brenta
  2008-12-11  1:03     ` Randy Brukardt
  0 siblings, 2 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-07  8:44 UTC (permalink / raw)


On Sat, 6 Dec 2008 09:10:49 -0800 (PST), Ludovic Brenta wrote:

> Dmitry A. Kazakov wrote:

>> It is absolutely unacceptable to me that a correct
>> program might fail at run-time because of accessibility checks.
> 
> I differ here; to me, a program that fails an accessibility check at
> run time is incorrect.

Ah, I used to think this way too. But then I realized that this form of
constraint is not a semantic one. Comparing to the constraint range 1..10,
accessibility constraint is an implementation detail. It has no semantic
meaning. When you assign a value outside the range that is semantically
incorrect. When you assign a pointer that potentially might become
dangling, that has no semantic meaning. The pointer is not yet dangling.
The program correctness depends on whether it will become dangling.

>> The only
>> case I could buy it, if exceptions where contracted, so that I would get an
>> compile-time error at some other place. Like "Constraint_Error may be
>> propagated, but the contract states otherwise."
> 
> In my understanding, there is an implicit contract stating that all
> subprograms may raise at least Program_Error, Storage_Error or
> Constraint_Error.

That must be changed.

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



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

* Re: Run-time accessibility checks
  2008-12-07  8:44   ` Run-time accessibility checks Dmitry A. Kazakov
@ 2008-12-07 14:56     ` Ludovic Brenta
  2008-12-07 19:22       ` Dmitry A. Kazakov
  2008-12-11  1:03     ` Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Ludovic Brenta @ 2008-12-07 14:56 UTC (permalink / raw)


On Dec 7, 9:44 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> On Sat, 6 Dec 2008 09:10:49 -0800 (PST), Ludovic Brenta wrote:
> > Dmitry A. Kazakov wrote:
> >> It is absolutely unacceptable to me that a correct
> >> program might fail at run-time because of accessibility checks.
>
> > I differ here; to me, a program that fails an accessibility check at
> > run time is incorrect.
>
> Ah, I used to think this way too. But then I realized that this form of
> constraint is not a semantic one. Comparing to the constraint range 1..10,
> accessibility constraint is an implementation detail. It has no semantic
> meaning. When you assign a value outside the range that is semantically
> incorrect. When you assign a pointer that potentially might become
> dangling, that has no semantic meaning. The pointer is not yet dangling.
> The program correctness depends on whether it will become dangling.

My definition of correctness is a bit more demanding. I want to be
*certain* that the pointer *cannot* become dangling, *ever*,
especially in the face of software maintenance where the program
changes. That's what accessibility checks give me, and I am grateful
for their existence and I will design my programs so as not to fail
accessibility checks.

--
Ludovic Brenta.



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

* Re: Run-time accessibility checks
  2008-12-07 14:56     ` Ludovic Brenta
@ 2008-12-07 19:22       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-07 19:22 UTC (permalink / raw)


On Sun, 7 Dec 2008 06:56:49 -0800 (PST), Ludovic Brenta wrote:

> On Dec 7, 9:44 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>> On Sat, 6 Dec 2008 09:10:49 -0800 (PST), Ludovic Brenta wrote:
>>> Dmitry A. Kazakov wrote:
>>>> It is absolutely unacceptable to me that a correct
>>>> program might fail at run-time because of accessibility checks.
>>
>>> I differ here; to me, a program that fails an accessibility check at
>>> run time is incorrect.
>>
>> Ah, I used to think this way too. But then I realized that this form of
>> constraint is not a semantic one. Comparing to the constraint range 1..10,
>> accessibility constraint is an implementation detail. It has no semantic
>> meaning. When you assign a value outside the range that is semantically
>> incorrect. When you assign a pointer that potentially might become
>> dangling, that has no semantic meaning. The pointer is not yet dangling.
>> The program correctness depends on whether it will become dangling.
> 
> My definition of correctness is a bit more demanding. I want to be
> *certain* that the pointer *cannot* become dangling, *ever*,
> especially in the face of software maintenance where the program
> changes. That's what accessibility checks give me, and I am grateful
> for their existence and I will design my programs so as not to fail
> accessibility checks.

No, it is *less* demanding than mine. Mine is that the program is either
correct or not, statically. This leaves no room for run-time checks on
correctness. Consequently, if accessibility check fails at run-time then a
correct program shall handle the corresponding exception. It does not add
safety.

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



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

* Re: Run-time accessibility checks (was: Construction initialization problem)
  2008-12-06 10:15 Run-time accessibility checks (was: Construction initialization problem) Dmitry A. Kazakov
  2008-12-06 17:10 ` Ludovic Brenta
@ 2008-12-11  0:55 ` Randy Brukardt
  2008-12-11  9:48   ` Run-time accessibility checks Dmitry A. Kazakov
  2008-12-11 22:15   ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
  1 sibling, 2 replies; 20+ messages in thread
From: Randy Brukardt @ 2008-12-11  0:55 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:txbc0ucekvix.ntpy85qsan7h$.dlg@40tude.net...
> On Fri, 5 Dec 2008 19:42:40 -0600, Randy Brukardt wrote:
...
>> I think that I might be able to fix the problem in the context of the
>> containers only, and for dereference of the objects only, but it is not
>> clear that the fix is worth the effort.
>
> It certainly does not. IMO Ada needs "setters" with the syntax sugar of an
> assignment, it does not need outward access types. The whole idea is just
> not Ada.

Well, I've thought about that, but I don't see a decent way to describe 
read/write semantics other than with an access type. Specifically, I was 
trying to figure out a user-defined dereference operation. One would presume 
that we would use an operator function for that, but what would it look 
like? The obvious answer of:

    function "all" (Obj : in Some_Type) return access Some_Other_Type;

has the accessibility issues. And something like:

   function "all" (Obj : in Some_Type) return Some_Other_Type;

means that you have (usually) copy semantics and in any case no assignment 
into. That doesn't really fix anything.

You certainly can't have a procedure ":=" to do assignment in because of 
discrimant-dependent components. That's never going to change for Ada, so 
please forget that.

I suppose you could have a component setter, but that requires a procedure 
with two names:

    procedure <component>.":=" (Target : in out Some_Tagged_Type; Source : 
in Some_Other_Type);

which would then be used as:

    Target.<component> := Source;

But that looks like a giant change to the Ada models, almost certainly out 
of scope for this current round. And it certainly means no useful iterators. 
And it also isn't very flexible -- where does the Cursor of a container go?? 
And so on.

                                Randy.





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

* Re: Run-time accessibility checks
  2008-12-07  8:44   ` Run-time accessibility checks Dmitry A. Kazakov
  2008-12-07 14:56     ` Ludovic Brenta
@ 2008-12-11  1:03     ` Randy Brukardt
  2008-12-11  9:08       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2008-12-11  1:03 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:ggyyafzb06rk.1fkbqhnepowug$.dlg@40tude.net...
> On Sat, 6 Dec 2008 09:10:49 -0800 (PST), Ludovic Brenta wrote:
>
>> Dmitry A. Kazakov wrote:
>
>>> It is absolutely unacceptable to me that a correct
>>> program might fail at run-time because of accessibility checks.
>>
>> I differ here; to me, a program that fails an accessibility check at
>> run time is incorrect.
>
> Ah, I used to think this way too. But then I realized that this form of
> constraint is not a semantic one. Comparing to the constraint range 1..10,
> accessibility constraint is an implementation detail. It has no semantic
> meaning. When you assign a value outside the range that is semantically
> incorrect. When you assign a pointer that potentially might become
> dangling, that has no semantic meaning. The pointer is not yet dangling.
> The program correctness depends on whether it will become dangling.

You are wrong here; that occurs when an *static* accessibility check is 
triggered that has to be checked at runtime because the source has dynamic 
accessibility. That conversion between worlds is the problem. IMHO, the 
static accessibility model is a pile of steaming dung - it never, ever works 
(I have yet to successfully write 'Access in anything outside of ACATS 
tests). OTOH, a fully dynamic model would only fail when the pointer really 
is dangling, because the accessibility would stay with the access type and 
there would never be any conversion to the static world. So that would only 
represent a real bug. But of course it is a lot more expensive at runtime.

I'm going to write up a proposal for a fully dynamic model. I don't really 
expect it to get anywhere, but at least we'll have it around the next time 
someone starts realizing that static accessibility is complete junk.

                               Randy.

P.S. Although it is not completely clear from the Standard, Ada has two 
virtually separate sets of definitions for static accessibility and 
"dynamic" accessibility (the latter is called just plain "accessibility" to 
add to the confusion). It's the static model that is such a mess; the 
dynamic model is just fine.


                                        Randy.









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

* Re: Run-time accessibility checks
  2008-12-11  1:03     ` Randy Brukardt
@ 2008-12-11  9:08       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-11  9:08 UTC (permalink / raw)


On Wed, 10 Dec 2008 19:03:23 -0600, Randy Brukardt wrote:

> OTOH, a fully dynamic model would only fail when the pointer really 
> is dangling, because the accessibility would stay with the access type and 
> there would never be any conversion to the static world. So that would only 
> represent a real bug. But of course it is a lot more expensive at runtime.

So far the problem is that accessibility check suggests that a pointer is
dangled when it is actually not.

> I'm going to write up a proposal for a fully dynamic model. I don't really 
> expect it to get anywhere, but at least we'll have it around the next time 
> someone starts realizing that static accessibility is complete junk.

Well, but I just don't need that stuff from the compiler. It merely blows
the language up giving nothing in return. When I (forced to) use a pointer
I know a lot more about the life time of the objects involved than the
compiler. I just want be able to express this semantics myself. For this I
need fat pointers with the "fat" defined myself. Give the programmer
abstract access types and scrap this dynamic accessibility stuff
altogether. [And anonymous access types as well.]

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



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

* Re: Run-time accessibility checks
  2008-12-11  0:55 ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
@ 2008-12-11  9:48   ` Dmitry A. Kazakov
  2008-12-11 11:21     ` Georg Bauhaus
  2008-12-11 22:15   ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-11  9:48 UTC (permalink / raw)


On Wed, 10 Dec 2008 18:55:41 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:txbc0ucekvix.ntpy85qsan7h$.dlg@40tude.net...
>> On Fri, 5 Dec 2008 19:42:40 -0600, Randy Brukardt wrote:
> ...
>>> I think that I might be able to fix the problem in the context of the
>>> containers only, and for dereference of the objects only, but it is not
>>> clear that the fix is worth the effort.
>>
>> It certainly does not. IMO Ada needs "setters" with the syntax sugar of an
>> assignment, it does not need outward access types. The whole idea is just
>> not Ada.
> 
> Well, I've thought about that, but I don't see a decent way to describe 
> read/write semantics other than with an access type. Specifically, I was 
> trying to figure out a user-defined dereference operation. One would presume 
> that we would use an operator function for that, but what would it look 
> like? The obvious answer of:
> 
>     function "all" (Obj : in Some_Type) return access Some_Other_Type;
> 
> has the accessibility issues. And something like:
> 
>    function "all" (Obj : in Some_Type) return Some_Other_Type;
> 
> means that you have (usually) copy semantics and in any case no assignment 
> into. That doesn't really fix anything.

No, you cannot solve it this way. A referential type (Some_Type) has to be
related to the target type (Some_Other_Type). Your first solution is to
replace one referential type with another built-in type (access
Some_Other_Type), that obviously does not change the semantics. Your second
solution is to replace it by the target type itself, no wonder that you
need a copy for that.

My solution is inheritance, disliked so much. If you want a referential
type to be a substitute for the target type, then the referential type
simply must  inherit to the target. (We don't need "all", though it can be
preserved using some intermediate referential type.) So the only thing
needed is interface inheritance from concrete types:

   type Ref_Type is private new Target_Type with private;

"private new" tells that only the interface of Target_Type is inherited,
the implementation is provided anew:

private   -- Privately it is just a plain pointer:
   type Ref_Type is access all Target_Type;

Because Ref_Type is not abstract, you will have to override all primitive
operations of Target_Type, and assignment must be a primitive operation,
and components getter/setters of, in case Target_Type were a record type,
must be as well.

> You certainly can't have a procedure ":=" to do assignment in because of 
> discrimant-dependent components.

":=" is a statement. What I would do is to define *two* primitive
subprograms the compiler will use in order to compose *one* ":=". The first
operation will determine the discriminants, the second will continue with
those known.

> I suppose you could have a component setter, but that requires a procedure 
> with two names:
> 
>     procedure <component>.":=" (Target : in out Some_Tagged_Type; Source : 
> in Some_Other_Type);
> 
> which would then be used as:
> 
>     Target.<component> := Source;

This is what I call abstract record interface. For each component it will
have two operations:

   function ".<component>" (R : Abstract_Record_Type)
      return Component_Type is abstract;
   procedure ".<component>"
      (R : in out Abstract_Record_Type; C : Component_Type) is abstract;

The compiler uses the second (setter) for all LHS X.Component.

> But that looks like a giant change to the Ada models, almost certainly out 
> of scope for this current round. And it certainly means no useful iterators. 

Records are not iterated. If we want a container to support iterations,
that must be an abstract array. It also was getter and setters:

   function "()" (A : Abstract_Array_Type; I : Index_Type)
      return Element_Type is abstract;
   procedure "()"
      (A : in out Abstract_Array_Type; I : Index_Type; E : Element_Type)
         is abstract;

> And it also isn't very flexible -- where does the Cursor of a container go??

To me to the recycle bin. *BUT* there is no any problem with cursors,
absolutely. A cursors is a pair. The first component is a type derived from
the container's interface (a reference to the container), the second
component is the container's index. Done!

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



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

* Re: Run-time accessibility checks
  2008-12-11  9:48   ` Run-time accessibility checks Dmitry A. Kazakov
@ 2008-12-11 11:21     ` Georg Bauhaus
  2008-12-11 11:40       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Georg Bauhaus @ 2008-12-11 11:21 UTC (permalink / raw)


Dmitry A. Kazakov schrieb:

> This is what I call abstract record interface. For each component it will
> have two operations:
> 
>    function ".<component>" (R : Abstract_Record_Type)
>       return Component_Type is abstract;
>    procedure ".<component>"
>       (R : in out Abstract_Record_Type; C : Component_Type) is abstract;
> 
> The compiler uses the second (setter) for all LHS X.Component.

That with pre/post/invariant constraints, in case the
component setting procedure has access to the object
containing the component.
Could pre/post/invariant also help when checking order of
component assignments?

(These are called "assigner commands" in Eiffel.)



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

* Re: Run-time accessibility checks
  2008-12-11 11:21     ` Georg Bauhaus
@ 2008-12-11 11:40       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-11 11:40 UTC (permalink / raw)


On Thu, 11 Dec 2008 12:21:34 +0100, Georg Bauhaus wrote:

> Dmitry A. Kazakov schrieb:
> 
>> This is what I call abstract record interface. For each component it will
>> have two operations:
>> 
>>    function ".<component>" (R : Abstract_Record_Type)
>>       return Component_Type is abstract;
>>    procedure ".<component>"
>>       (R : in out Abstract_Record_Type; C : Component_Type) is abstract;
>> 
>> The compiler uses the second (setter) for all LHS X.Component.
> 
> That with pre/post/invariant constraints, in case the
> component setting procedure has access to the object
> containing the component.

It is a primitive operation of the abstract record type, but not of the
component. If you wanted to have it a primitive operation of both, you
would have to support MD, which is I don't know how to do (properly).

> Could pre/post/invariant also help when checking order of
> component assignments?

Which order? A record type does not declare any specific access order for
its components. If you have record aggregates in mind that is another
interface and another issue. Aggregate is a form of a constructor with some
special syntax.

> (These are called "assigner commands" in Eiffel.)

There are pretty clear rules about what happens with pre/post/invariant
upon inheritance (Liskov). The only problem is that many people (like Meyer
and possibly you) honestly believe they could make pre/post/invariant
dynamic. Count me out.

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



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

* Re: Run-time accessibility checks (was: Construction initialization problem)
  2008-12-11  0:55 ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
  2008-12-11  9:48   ` Run-time accessibility checks Dmitry A. Kazakov
@ 2008-12-11 22:15   ` Randy Brukardt
  2008-12-11 22:31     ` Randy Brukardt
  2008-12-12  9:21     ` Dmitry A. Kazakov
  1 sibling, 2 replies; 20+ messages in thread
From: Randy Brukardt @ 2008-12-11 22:15 UTC (permalink / raw)


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

> My solution is inheritance, disliked so much. If you want
> a referential type to be a substitute for the target type, then the 
> referential
> type simply must  inherit to the target. (We don't need "all", though it 
> can be preserved using some intermediate referential type.)

Well, this doesn't make any sense to me at all. And the following example 
doesn't help; you've made it the *same* type, which is definitely not what 
you want. The result of dereferencing an access value is a *different* type, 
with *different* operations. I don't *want* interchangability!!

...
> Because Ref_Type is not abstract, you will have to override all primitive 
> operations of Target_Type, and assignment must be a primitive operation, 
> and components getter/setters of, in case Target_Type were a record type, 
> must be as well.

That sounds like a maintenance headache (any change must be replicated 
everywhere. That became such a pain for the Claw Builder program that it 
almost ground development on it to a halt.)

...
>> You certainly can't have a procedure ":=" to do assignment in because of 
>> discrimant-dependent components.

> ":=" is a statement. What I would do is to define *two* primitive 
> subprograms the compiler will use in order to compose *one* ":=". The 
> first operation will determine the discriminants, the second will continue 
> with those known.

That's not the problem; the problem is that components appear and disappear, 
and there is no way to assign them. And there is no way in Ada to just set 
the discriminants without giving values to the components as well; that is a 
fundamental invariant of the language which I don't think can be changed 
without making everything erroneous.

...
> Records are not iterated. If we want a container to support iterations, 
> that must be an abstract array. It also was getter and setters:
>    function "()" (A : Abstract_Array_Type; I : Index_Type) return 
> Element_Type is abstract; procedure "()" (A : in out Abstract_Array_Type; 
> I : Index_Type; E : Element_Type) is abstract;

That's not flexible enough for iteration; the index can be anything (it need 
not have an inherent ordering; it surely cannot be restricted to a discrete 
type) and thus just having this interface does not allow iteration.

There also is very little chance of such an interface being supported in 
Ada, if I read the feelings of the group well enough. One concern I've heard 
is that there is no practical way to support this for slicing (again, 
because the index does not necessarily have ordering). Personally, I'd give 
up slicing for this sort of abstraction, but I don't think that will fly.

Another concern is that almost all of the existing predefined packages would 
have to be scrapped and replaced to make any use of this (especially the 
string packages). But people aren't willing to do that ("insufficiently 
broken"), even if there is plenty of evidence that we could do a lot better 
for those packages.

>> And it also isn't very flexible -- where does the Cursor of a container 
>> go??

> To me to the recycle bin. *BUT* there is no any problem with cursors, 
> absolutely. A cursors is a pair. The first component is a type derived 
> from the container's interface (a reference to the container), the second 
> component is the container's index. Done!

The cursor is the index in the model you have here. And it already is a pair 
(container, access to something). Not sure what you dislike about them; 
they've have the same semantics if not the same name. (I was talking about a 
record selector interface, which makes more sense for getting individual 
elements.) What *cannot* be the case is that the index is required to be 
some sort of discrete type. That would require a map to translate said index 
into some sort of access to the actual element. But that would be silly, 
especially for map containers (you'd have to go through two maps to find 
anything, and for what??)

But the real problem in all of these things you've suggested is that they 
are all technically by-copy for reading. If that is all you want, the 
existing Ada containers do that just fine. The problem is that if the 
elements are large, copying them may be very expensive, so a by-reference 
access method is reading. That's the core of the problem I'm trying to 
address (because I think there is a chance that people will view it as 
significant enough to deal with). Functions returning values of a type *do 
not* provide any solution to that (and cannot).

                                        Randy. 





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

* Re: Run-time accessibility checks (was: Construction initialization problem)
  2008-12-11 22:15   ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
@ 2008-12-11 22:31     ` Randy Brukardt
  2008-12-13  0:49       ` Randy Brukardt
  2008-12-12  9:21     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2008-12-11 22:31 UTC (permalink / raw)


I said:

> ...
>> Because Ref_Type is not abstract, you will have to override all primitive 
>> operations of Target_Type, and assignment must be a primitive operation, 
>> and components getter/setters of, in case Target_Type were a record type, 
>> must be as well.
>
> That sounds like a maintenance headache (any change must be replicated 
> everywhere. That became such a pain for the Claw Builder program that it 
> almost ground development on it to a halt.)

By the way, if you don't care about the maintenance headache, you can do 
this with Ada today, using interfaces. Since an interface requires all of 
the operations to be redefined, you get exactly this behavior as long you 
define both types to inherit from the interface (not each other). That is:

type Something_Interface is interface;
<operations>

type Target_Type is new Something_Interface;
<implement operations>

type Ref_Type is new Something_Interface;
<reimplement operations>

I'm not sure what you need that can't be done this way. (I'm certain that no 
new feature is going to get added to the language if it is equivalent to 
what you can already do and doesn't even save much typing).

                                Randy.





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

* Re: Run-time accessibility checks
  2008-12-11 22:15   ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
  2008-12-11 22:31     ` Randy Brukardt
@ 2008-12-12  9:21     ` Dmitry A. Kazakov
  1 sibling, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-12  9:21 UTC (permalink / raw)


On Thu, 11 Dec 2008 16:15:39 -0600, Randy Brukardt wrote:

>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote
> 
>> My solution is inheritance, disliked so much. If you want
>> a referential type to be a substitute for the target type, then the 
>> referential type simply must  inherit to the target. (We don't need "all", though it 
>> can be preserved using some intermediate referential type.)
> 
> Well, this doesn't make any sense to me at all. And the following example 
> doesn't help; you've made it the *same* type, which is definitely not what 
> you want.

No I made it having same interface, the implementation is different. You
have a wrong model in mind. Same interface does not imply same
representation / implementation.

> The result of dereferencing an access value is a *different* type, 
> with *different* operations. I don't *want* interchangability!!

Then you have what you have - an inability to assign an element in the
container, *because* it is of a different type. In my solution the
container element does not magically change its type, just because you
don't want to copy it. Why should it? The container knows how to access its
elements.

>> Because Ref_Type is not abstract, you will have to override all primitive 
>> operations of Target_Type, and assignment must be a primitive operation, 
>> and components getter/setters of, in case Target_Type were a record type, 
>> must be as well.
> 
> That sounds like a maintenance headache (any change must be replicated 
> everywhere. That became such a pain for the Claw Builder program that it 
> almost ground development on it to a halt.)

That is another issue. Ada has no good support for delegation. You should
be able to delegate Target.Operation to Ref_Type.all.Operation without
writing boring wrappers. It is not specific to this case.

>>> You certainly can't have a procedure ":=" to do assignment in because of 
>>> discrimant-dependent components.
> 
>> ":=" is a statement. What I would do is to define *two* primitive 
>> subprograms the compiler will use in order to compose *one* ":=". The 
>> first operation will determine the discriminants, the second will continue 
>> with those known.
> 
> That's not the problem; the problem is that components appear and disappear, 
> and there is no way to assign them.

I don't see any problem. All discriminants are known in the *second*
primitive operation. That allows you to write a case statement and assign
existing components.

> And there is no way in Ada to just set 
> the discriminants without giving values to the components as well; that is a 
> fundamental invariant of the language which I don't think can be changed 
> without making everything erroneous.

You don't need it. The *first* primitive operation does not deal with the
values. The idea is very simple. For each type T there is a predefined type
T'Constraint defined as a tuple of discriminants (array bounds, type tags)
of T. For example, when

   type T (X : Integer) is record
      case X is ...
      end case;
   end record;

then

   type T'Constraint (X : Integer) is null record;

Now the *first* primitive operation determines T'Constraint. The *second*
primitive operation is called either on an object with the constraints set
from the result of the *first* operation or else with a value of
T'Constraint. That is it:

   procedure Set (T : in out Object);  or
   function Set (Constraint : T'Constraint) return T;

>> Records are not iterated. If we want a container to support iterations, 
>> that must be an abstract array. It also was getter and setters:
>>    function "()" (A : Abstract_Array_Type; I : Index_Type) return 
>> Element_Type is abstract; procedure "()" (A : in out Abstract_Array_Type; 
>> I : Index_Type; E : Element_Type) is abstract;
> 
> That's not flexible enough for iteration; the index can be anything (it need 
> not have an inherent ordering; it surely cannot be restricted to a discrete 
> type) and thus just having this interface does not allow iteration.

I proposed to introduce unordered arrays long time ago.

> There also is very little chance of such an interface being supported in 
> Ada, if I read the feelings of the group well enough. One concern I've heard 
> is that there is no practical way to support this for slicing (again, 
> because the index does not necessarily have ordering). Personally, I'd give 
> up slicing for this sort of abstraction, but I don't think that will fly.

I think it is solvable. First we have to introduce abstract index types.
Ada lacks this abstraction completely. If we had index types we could make
ranges first-class citizens. That would allow to solve slicing.

> Another concern is that almost all of the existing predefined packages would 
> have to be scrapped and replaced to make any use of this (especially the 
> string packages). But people aren't willing to do that ("insufficiently 
> broken"), even if there is plenty of evidence that we could do a lot better 
> for those packages.

Why scrapped? Simply moved to the Annex J (:-))

>>> And it also isn't very flexible -- where does the Cursor of a container 
>>> go??
> 
>> To me to the recycle bin. *BUT* there is no any problem with cursors, 
>> absolutely. A cursors is a pair. The first component is a type derived 
>> from the container's interface (a reference to the container), the second 
>> component is the container's index. Done!
> 
> The cursor is the index in the model you have here. And it already is a pair 
> (container, access to something).

To me index is an instance of an abstract ordered or unordered index type.
Its values are unrelated to any specific container. Cursor is an index + a
specific container.

> Not sure what you dislike about them; 
> they've have the same semantics if not the same name. (I was talking about a 
> record selector interface, which makes more sense for getting individual 
> elements.) 

Referential semantics is what I dislike in cursors. Cursor is a dressed
pointer. It is very difficult to use it in concurrent/volatile environment.
It is inherently unsafe, what happens with it upon container update? Where
is that described? How to prevent update when a cursor is still there. And
so on, and so forth. Cursor is a bad, crippled thing.

> What *cannot* be the case is that the index is required to be 
> some sort of discrete type.

Right, that must be an abstract interface, which any type could implement.

> That would require a map to translate said index 
> into some sort of access to the actual element. But that would be silly, 
> especially for map containers (you'd have to go through two maps to find 
> anything, and for what??)

You have pointer model in mind. But there is no pointers in my world. There
is a setter operation. The setter takes an index argument, it is not my
business to look into the implementation of.

> But the real problem in all of these things you've suggested is that they 
> are all technically by-copy for reading. If that is all you want, the 
> existing Ada containers do that just fine. The problem is that if the 
> elements are large, copying them may be very expensive, so a by-reference 
> access method is reading. That's the core of the problem I'm trying to 
> address (because I think there is a chance that people will view it as 
> significant enough to deal with). Functions returning values of a type *do 
> not* provide any solution to that (and cannot).

This makes no sense to me. Reading is not an operation. If a primitive
operation of Element_Type has to be called on an element of Container_Type
specified by Index_Type, that is not "reading." If you mean "functional"
appearance of "getter," them firstly, it is not obvious why the getter is
to be used to achieve the goal, and secondly return by reference is marked
as "solved" in Ada 2005. Those Pickwickian functions were praised for that,
or? (:-))

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



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

* Re: Run-time accessibility checks (was: Construction initialization problem)
  2008-12-11 22:31     ` Randy Brukardt
@ 2008-12-13  0:49       ` Randy Brukardt
  2008-12-13  9:06         ` Run-time accessibility checks Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2008-12-13  0:49 UTC (permalink / raw)


>> "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote
...
>> The result of dereferencing an access value is a *different* type, with 
>> *different* operations. I don't *want* interchangability!!
>
>
>Then you have what you have - an inability to assign an element in the 
>container, *because* it is of a different type. In my solution the 
>container element does not magically change its type, just because you 
>don't want to copy it. Why should it? The container knows how to access its 
>elements.

It sounds to me like you want container of X to have the operations of X. 
They're not the same thing! That way lies madness, especially in that the 
implementation costs will be very high. If you want that kind of 
abstraction, I think you have to go to a fully dynamic language (which Ada 
is not and never will be).

I'm not going to discuss this further, because you're clearly on the dark 
side of this issue, and further discussion would be like trying to explain 
to "anon" why he's wrong. ;-) [I'm also not seeing your messages for some 
reason, had to grab this one off of Google Groups.]

...
>>> You certainly can't have a procedure ":=" to do assignment in because of 
>>> discrimant-dependent components.

>>> ":=" is a statement. What I would do is to define *two* primitive 
>>> subprograms the compiler will use in order to compose *one* ":=". The 
>>> first operation will determine the discriminants, the second will 
>>> continue with those known.

>> That's not the problem; the problem is that components appear and 
>> disappear, and there is no way to assign them.

>I don't see any problem. All discriminants are known in the *second* 
>primitive operation. That allows you to write a case statement and assign 
>existing components.

You're solving the wrong problem. (Yes, I did read the rest of the message 
before replying here.) There is no problem with overriding the top-level 
assignment operation, never has been. The problem is composition (which is 
necessary so that the invariants of an abstraction are preserved). A 
component does not know nor care about the discriminants of the object that 
it is a component of. And it could not, in general, or again you have 
descended into madness (no type can enumerate all of the places it could 
possibility be used).

...

...
>> Not sure what you dislike about them; they've have the same semantics if 
>> not the same name. (I was talking about a record selector interface, 
>> which makes more sense for getting individual elements.)
>
> Referential semantics is what I dislike in cursors. Cursor is a dressed 
> pointer. It is very difficult to use it in concurrent/volatile 
> environment. It is inherently unsafe, what happens with it upon container 
> update? Where is that described? How to prevent update when a cursor is 
> still there. And so on, and so forth. Cursor is a bad, crippled thing.

The semantics of cursors are described in great detail in the language 
description. The short of it is that updating the container is certain ways 
while the cursor is outstanding is a bounded error. Either the cursor still 
points to the element, or Program_Error is raised. (Ignore Vector cursors 
for the moment, they're something else altogether.) Erroneousness is only 
allowed when the container itself is destroyed (such as with 
Unchecked_Deallocation).

As far as a concurrent environment goes, containers in general don't work 
well in such environments. You can define some special cases that make 
sense, but in general you have to have a protected environment that wraps 
the container. Cursors might make that worse, but surely are not the whole 
problem -- for instance, it is pretty much impossible to create a safe 
iterator for a general container in a concurrent environment. You have to 
lock the entire object for the entire time the iterator is active, and that 
pretty much kills concurrency.

And in any case, as one who is telling me that I'm thinking too low-level, 
it obvious that you are not looking at the abstraction of the cursor. All of 
cursor is logically is a means to find (reference - for the lack of a better 
word) an element in a container. You've called that abstraction an index, 
but it is the exact same abstraction. And it would need the exact same rules 
for updates and the like, giving the same effects that you don't like.

...
>> That would require a map to translate said index into some sort of access 
>> to the actual element. But that would be silly, especially for map 
>> containers (you'd have to go through two maps to find anything, and for 
>> what??)

> You have pointer model in mind. But there is no pointers in my world. 
> There is a setter operation. The setter takes an index argument, it is not 
> my business to look into the implementation of.

Well, *someone* has to worry about the implementation model, and that is 
what I was talking about. It doesn't matter how wonderful the abstraction is 
if no one can implement it efficiently. Requiring a map to use a map to 
resolve its cursors is definitely insane.

>> But the real problem in all of these things you've suggested is that they 
>> are all technically by-copy for reading. If that is all you want, the 
>> existing Ada containers do that just fine. The problem is that if the 
>> elements are large, copying them may be very expensive, so a by-reference 
>> access method is reading. That's the core of the problem I'm trying to 
>> address (because I think there is a chance that people will view it as 
>> significant enough to deal with). Functions returning values of a type 
>> *do not* provide any solution to that (and cannot).

>This makes no sense to me. Reading is not an operation. If a primitive 
>operation of Element_Type has to be called on an element of Container_Type 
>specified by Index_Type, that is not "reading." If you mean "functional" 
>appearance of "getter," them firstly, it is not obvious why the getter is 
>to be used to achieve the goal, and secondly return by reference is marked 
>as "solved" in Ada 2005. Those Pickwickian functions were praised for that, 
>or? (:-))

As I said previously, container of X is not an X, and trying to make the two 
equivalent is the height of insanity.

And return-by-reference was removed from Ada 2005, not "solved". It didn't 
work in Ada 95, and it doesn't work in Ada 2005. No problem there. ;-)

                                               Randy.





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

* Re: Run-time accessibility checks
  2008-12-13  0:49       ` Randy Brukardt
@ 2008-12-13  9:06         ` Dmitry A. Kazakov
  2008-12-16  1:53           ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-13  9:06 UTC (permalink / raw)


On Fri, 12 Dec 2008 18:49:39 -0600, Randy Brukardt wrote:

>>> "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote
> ...
>>> The result of dereferencing an access value is a *different* type, with 
>>> *different* operations. I don't *want* interchangability!!
>>
>>Then you have what you have - an inability to assign an element in the 
>>container, *because* it is of a different type. In my solution the 
>>container element does not magically change its type, just because you 
>>don't want to copy it. Why should it? The container knows how to access its 
>>elements.
> 
> It sounds to me like you want container of X to have the operations of X. 
> They're not the same thing! That way lies madness, especially in that the 
> implementation costs will be very high. If you want that kind of 
> abstraction, I think you have to go to a fully dynamic language (which Ada 
> is not and never will be).

Not necessary. What I want is to leave the decision to the programmer.

BTW, it is another case, you are considering now:

   Op (C (I))

You suggest that this should *always* mean:

1.  Op (Dereference (Get_Element_Access (C, I)))

But this is not the only possible way.

2. The variant you didn't like uses no access types

   Op (C, I)

but requires C to inherit a modified interface of its elements. I see
nothing wrong with that.

3. The variant which applies beloved access to the operation rather than to
the element:

   Do (C, I, Op'Access)

References to operations should be no problem, especially because it is a
inward closure, while in the variant 1 you have an outward reference
(=never works).

As for implementation costs of the variant 2, in any case they are not of
the compiler designer. As a programmer I am ready to pay them, because
there is a huge echelon of secondary problems you can't even approach with
1 or 3. They are simply unsolvable - a container of subtypes which is a
subtype of container of parent types etc. The variant 2 opens that door.
What is behind, I don't know.

> I'm not going to discuss this further, because you're clearly on the dark 
> side of this issue, and further discussion would be like trying to explain 
> to "anon" why he's wrong. ;-)

I am the only one who uses all Ada 2005? (:-))

> [I'm also not seeing your messages for some 
> reason, had to grab this one off of Google Groups.]

Is your mail reader in Ada? (:-))

>>>> You certainly can't have a procedure ":=" to do assignment in because of 
>>>> discrimant-dependent components.
> 
>>>> ":=" is a statement. What I would do is to define *two* primitive 
>>>> subprograms the compiler will use in order to compose *one* ":=". The 
>>>> first operation will determine the discriminants, the second will 
>>>> continue with those known.
> 
>>> That's not the problem; the problem is that components appear and 
>>> disappear, and there is no way to assign them.
> 
>>I don't see any problem. All discriminants are known in the *second* 
>>primitive operation. That allows you to write a case statement and assign 
>>existing components.
> 
> You're solving the wrong problem. (Yes, I did read the rest of the message 
> before replying here.) There is no problem with overriding the top-level 
> assignment operation, never has been. The problem is composition (which is 
> necessary so that the invariants of an abstraction are preserved). A 
> component does not know nor care about the discriminants of the object that 
> it is a component of. And it could not, in general, or again you have 
> descended into madness (no type can enumerate all of the places it could 
> possibility be used).

But discriminants leak anyway. You cannot have an unconstrained component
without passing its constraint in some form to the container. If that is a
broken abstraction, then it is already broken by someone else. The
container type knows its actual components and assigns them. What else
composition is needed?

> You've called that abstraction an index, but it is the exact same abstraction.

The difference can be illustrate on:

   A (I) = B (I)

The index value I applies to any container that uses it, independently on
the container content. You can have an index without any container:

   for I in 1..200 loop
       Put_Line ("Hallo!");  -- No any containers in sight
   end loop;

> And it would need the exact same rules 
> for updates and the like, giving the same effects that you don't like.

No, it is not an error to do anything with the container while thinking
about "the second element of." Cursor and index are fundamentally different
things. Indices do not persist, they do not require identity of the element
etc.

>> You have pointer model in mind. But there is no pointers in my world. 
>> There is a setter operation. The setter takes an index argument, it is not 
>> my business to look into the implementation of.
> 
> Well, *someone* has to worry about the implementation model, and that is 
> what I was talking about. It doesn't matter how wonderful the abstraction is 
> if no one can implement it efficiently. Requiring a map to use a map to 
> resolve its cursors is definitely insane.

How are you going to implement packed containers of bits stored in a
hardware register?

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



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

* Re: Run-time accessibility checks
  2008-12-13  9:06         ` Run-time accessibility checks Dmitry A. Kazakov
@ 2008-12-16  1:53           ` Randy Brukardt
  2008-12-16  9:28             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2008-12-16  1:53 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1xgim3qybjw07$.16nw9986hywhh.dlg@40tude.net...
...
> 2. The variant you didn't like uses no access types
>
>   Op (C, I)
>
> but requires C to inherit a modified interface of its elements. I see
> nothing wrong with that.

This isn't inheritance, as it requires adding a selector of some sort (you 
called it an index, Ada calls it a cursor) to the operations. At best, it is 
some sort of automatic synthesis of operations. But that again begs the 
question of how to describe what it does -- I don't see any reasonable way 
to do that. (How can you dispatch to an operation that has a different 
number of parameters???)

...
...
>> [I'm also not seeing your messages for some
>> reason, had to grab this one off of Google Groups.]
>
> Is your mail reader in Ada? (:-))

No, unfortunately. I don't have time to write a mail reader... compiler, web 
server, and mail server seem like enough of "build-your-own". :-)

...
>> You're solving the wrong problem. (Yes, I did read the rest of the 
>> message
>> before replying here.) There is no problem with overriding the top-level
>> assignment operation, never has been. The problem is composition (which 
>> is
>> necessary so that the invariants of an abstraction are preserved). A
>> component does not know nor care about the discriminants of the object 
>> that
>> it is a component of. And it could not, in general, or again you have
>> descended into madness (no type can enumerate all of the places it could
>> possibility be used).
>
> But discriminants leak anyway. You cannot have an unconstrained component
> without passing its constraint in some form to the container. If that is a
> broken abstraction, then it is already broken by someone else. The
> container type knows its actual components and assigns them. What else
> composition is needed?

You're claiming that every type that has a component of a type with 
user-defined assignment also must have a user-defined assignment? That's way 
too much work, and way too likely to get wrong.

>> You've called that abstraction an index, but it is the exact same 
>> abstraction.
>
> The difference can be illustrate on:
>
>   A (I) = B (I)
>
> The index value I applies to any container that uses it, independently on
> the container content. You can have an index without any container:
>
>   for I in 1..200 loop
>       Put_Line ("Hallo!");  -- No any containers in sight
>   end loop;
>
>> And it would need the exact same rules
>> for updates and the like, giving the same effects that you don't like.
>
> No, it is not an error to do anything with the container while thinking
> about "the second element of." Cursor and index are fundamentally 
> different
> things. Indices do not persist, they do not require identity of the 
> element
> etc.

That seems much more limiting than the cursor idea. It doesn't make any 
sense to talk about the "second" item of a (generic) container. Consider a 
map referenced by strings, for instance. Moreover, elements of many forms of 
container don't have any order, so you can't do anything useful with the 
index by itself -- but operations like iteration are still meaningful.

                                      Randy.





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

* Re: Run-time accessibility checks
  2008-12-16  1:53           ` Randy Brukardt
@ 2008-12-16  9:28             ` Dmitry A. Kazakov
  2008-12-16 22:21               ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-16  9:28 UTC (permalink / raw)


On Mon, 15 Dec 2008 19:53:02 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1xgim3qybjw07$.16nw9986hywhh.dlg@40tude.net...
> ...
>> 2. The variant you didn't like uses no access types
>>
>>   Op (C, I)
>>
>> but requires C to inherit a modified interface of its elements. I see
>> nothing wrong with that.
> 
> This isn't inheritance, as it requires adding a selector of some sort (you 
> called it an index, Ada calls it a cursor) to the operations. At best, it is 
> some sort of automatic synthesis of operations.

Yes.

> But that again begs the 
> question of how to describe what it does -- I don't see any reasonable way 
> to do that. (How can you dispatch to an operation that has a different 
> number of parameters???)

No, you are trying to automate it in the compiler. That is not needed. The
the compiler should do only two things:

1. Create interface of the container type. The compiler knows the interface
of the elements and the index type. It is trivial to produce the
corresponding abstract primitive operations: for each Op of the element
type it creates Op of container *without* implementation.

2. Replace any Op(C(I)) with Op(C,I)

That's all. The implementation of these operations is the programmer's
business. Dispatch is trivial, it is dispatching when C is class-wide.

We don't need yet another built-in container type. We need only an
interface of a container type. The implementation will be provided by the
programmer.

>>> You're solving the wrong problem. (Yes, I did read the rest of the 
>>> message
>>> before replying here.) There is no problem with overriding the top-level
>>> assignment operation, never has been. The problem is composition (which 
>>> is
>>> necessary so that the invariants of an abstraction are preserved). A
>>> component does not know nor care about the discriminants of the object 
>>> that
>>> it is a component of. And it could not, in general, or again you have
>>> descended into madness (no type can enumerate all of the places it could
>>> possibility be used).
>>
>> But discriminants leak anyway. You cannot have an unconstrained component
>> without passing its constraint in some form to the container. If that is a
>> broken abstraction, then it is already broken by someone else. The
>> container type knows its actual components and assigns them. What else
>> composition is needed?
> 
> You're claiming that every type that has a component of a type with 
> user-defined assignment also must have a user-defined assignment?

No. I want to be able to define an assignment.

(I don't want to extend Ada, I want to reduce it. We have much to many
built-in stuff, which should rather be provided at the library level.)

>>> You've called that abstraction an index, but it is the exact same 
>>> abstraction.
>>
>> The difference can be illustrate on:
>>
>>   A (I) = B (I)
>>
>> The index value I applies to any container that uses it, independently on
>> the container content. You can have an index without any container:
>>
>>   for I in 1..200 loop
>>       Put_Line ("Hallo!");  -- No any containers in sight
>>   end loop;
>>
>>> And it would need the exact same rules
>>> for updates and the like, giving the same effects that you don't like.
>>
>> No, it is not an error to do anything with the container while thinking
>> about "the second element of." Cursor and index are fundamentally 
>> different things. Indices do not persist, they do not require identity of the 
>> element etc.
> 
> That seems much more limiting than the cursor idea.

The inverse. Cursor requires persistent identity. It is an extremely strong
requirement with a number of nasty consequences (immovable elements for
example).

> It doesn't make any 
> sense to talk about the "second" item of a (generic) container.

That was an example when the index is an order. It is a property of the
index. No problem to have indices without order (for associative
containers).

> Consider a map referenced by strings, for instance.

Yes. In this case the index type is String. Where is any problem?

(Actually String is ordered. You likely meant another property: If I1, I2
in C, then I1<I<I2 in C, but that is no matter.)

> Moreover, elements of many forms of 
> container don't have any order, so you can't do anything useful with the 
> index by itself -- but operations like iteration are still meaningful.

No, if index is unordered and not dense, then iteration is meaningless. It
is a broken abstraction then. If you want to iterate a container you have
to order its elements. That is equivalent to existence some ordered dense
index of. The index can be of the type System.Address, that is no matter.
But to be able to iterate is a contract on the container. It is IMO a very
bad idea to assume all containers to fulfill this contract.

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



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

* Re: Run-time accessibility checks
  2008-12-16  9:28             ` Dmitry A. Kazakov
@ 2008-12-16 22:21               ` Randy Brukardt
  2008-12-17  8:54                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2008-12-16 22:21 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:k2ftogbqmojg.yrjw3ldbi604.dlg@40tude.net...
...
>> Moreover, elements of many forms of
>> container don't have any order, so you can't do anything useful with the
>> index by itself -- but operations like iteration are still meaningful.
>
> No, if index is unordered and not dense, then iteration is meaningless. It
> is a broken abstraction then. If you want to iterate a container you have
> to order its elements. That is equivalent to existence some ordered dense
> index of.

Not at all. You are saying that "forall" (that is, do something to all 
elements of a container) is not a useful iteration if the elements don't 
have an order. That's pretty hard to believe; indeed, the value of an 
iterator is is specifically because the order of the elements is not 
specified; without that, there is no way to get all of the elements via 
their cursors (or indexes, if you prefer).

> The index can be of the type System.Address, that is no matter.
> But to be able to iterate is a contract on the container. It is IMO a very
> bad idea to assume all containers to fulfill this contract.

I would never want to say *never* (there is always a counter-example), but 
surely all of the classic containers (including a "bag") need iteration. 
It's true that the implementation of a "bag" will necessarily impose an 
order on the elements, but that order is not interesting and shouldn't be 
considered part of the abstraction. But the ability to get all elements of a 
bag for processing is a fundamental operation of the container.

                              Randy.





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

* Re: Run-time accessibility checks
  2008-12-16 22:21               ` Randy Brukardt
@ 2008-12-17  8:54                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2008-12-17  8:54 UTC (permalink / raw)


On Tue, 16 Dec 2008 16:21:00 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:k2ftogbqmojg.yrjw3ldbi604.dlg@40tude.net...
> ...
>>> Moreover, elements of many forms of
>>> container don't have any order, so you can't do anything useful with the
>>> index by itself -- but operations like iteration are still meaningful.
>>
>> No, if index is unordered and not dense, then iteration is meaningless. It
>> is a broken abstraction then. If you want to iterate a container you have
>> to order its elements. That is equivalent to existence some ordered dense
>> index of.
> 
> Not at all. You are saying that "forall" (that is, do something to all 
> elements of a container) is not a useful iteration if the elements don't 
> have an order. That's pretty hard to believe; indeed, the value of an 
> iterator is is specifically because the order of the elements is not 
> specified; without that, there is no way to get all of the elements via 
> their cursors (or indexes, if you prefer).

Well, that is a philosophic-mathematical issue. I am on a constructivist's
position here. You cannot say "forall," without constructing a set in a way
that effectively enumerates its elements, which in turn is equivalent to a
contract on the set and the corresponding (there can be many) index of.
Clearly any set in a computer has such property, but it breaks abstraction.

>> The index can be of the type System.Address, that is no matter.
>> But to be able to iterate is a contract on the container. It is IMO a very
>> bad idea to assume all containers to fulfill this contract.
> 
> I would never want to say *never* (there is always a counter-example), but 
> surely all of the classic containers (including a "bag") need iteration. 
> It's true that the implementation of a "bag" will necessarily impose an 
> order on the elements, but that order is not interesting and shouldn't be 
> considered part of the abstraction. But the ability to get all elements of a 
> bag for processing is a fundamental operation of the container.

That is not a bag then. Consider an implementation of a bag that uses an
RDB as the store. You cannot iterate rows in an RDB. You can do only ones
of a result set. These are different sets, and the second set has an
extremely heavy penalty to build from the first (potentially
Storage_Error). Not providing iteration would be important for safe use.

But I don't see how this all can be an argument for cursor against index.
If the primary index is unordered that does not mean you cannot have
another one ordered. You can provide as many views of the container you
wished. If you want to iterate container in a loop, provide a view on it as
an array indexed by Positive. As simple as that.

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



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

end of thread, other threads:[~2008-12-17  8:54 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-06 10:15 Run-time accessibility checks (was: Construction initialization problem) Dmitry A. Kazakov
2008-12-06 17:10 ` Ludovic Brenta
2008-12-07  8:44   ` Run-time accessibility checks Dmitry A. Kazakov
2008-12-07 14:56     ` Ludovic Brenta
2008-12-07 19:22       ` Dmitry A. Kazakov
2008-12-11  1:03     ` Randy Brukardt
2008-12-11  9:08       ` Dmitry A. Kazakov
2008-12-11  0:55 ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
2008-12-11  9:48   ` Run-time accessibility checks Dmitry A. Kazakov
2008-12-11 11:21     ` Georg Bauhaus
2008-12-11 11:40       ` Dmitry A. Kazakov
2008-12-11 22:15   ` Run-time accessibility checks (was: Construction initialization problem) Randy Brukardt
2008-12-11 22:31     ` Randy Brukardt
2008-12-13  0:49       ` Randy Brukardt
2008-12-13  9:06         ` Run-time accessibility checks Dmitry A. Kazakov
2008-12-16  1:53           ` Randy Brukardt
2008-12-16  9:28             ` Dmitry A. Kazakov
2008-12-16 22:21               ` Randy Brukardt
2008-12-17  8:54                 ` Dmitry A. Kazakov
2008-12-12  9:21     ` Dmitry A. Kazakov

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