comp.lang.ada
 help / color / mirror / Atom feed
* Passing indefinite types
@ 2013-02-02 21:07 sbelmont700
  2013-02-02 21:31 ` Jeffrey Carter
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: sbelmont700 @ 2013-02-02 21:07 UTC (permalink / raw)


Hi,

Does anyone know of a slick way to pass several locally declared, indefinite types to a subprogram without resorting to the heap or Unchecked_Access?  An array of indefinite types is obviously not possible, an array of named access types is subject to accessibility problems, and wrapping the object in an 'accessor' (i.e. a null record with an access discriminant) turns right back into a problem of an array of indefinite types.  I can always declare a procedure that takes a bunch of individual parameters, but this seems like a kludge, and doesn't solve the problem if the number of items might vary.  It would be nice if there was some way to establish that a discriminated record is in fact a fixed size, or perhaps if an array of anonymous access types had the same accessibility as access discriminants.  But if anyone knows of a workaround, I would be interested in how it was done.

Thank you.

-sb




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

* Re: Passing indefinite types
  2013-02-02 21:07 Passing indefinite types sbelmont700
@ 2013-02-02 21:31 ` Jeffrey Carter
  2013-02-03  0:27   ` sbelmont700
  2013-02-03 10:22 ` gautier_niouzes
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 12+ messages in thread
From: Jeffrey Carter @ 2013-02-02 21:31 UTC (permalink / raw)


On 02/02/2013 02:07 PM, sbelmont700@gmail.com wrote:
>
> Does anyone know of a slick way to pass several locally declared, indefinite
> types to a subprogram without resorting to the heap or Unchecked_Access?  An
> array of indefinite types is obviously not possible, an array of named access
> types is subject to accessibility problems, and wrapping the object in an
> 'accessor' (i.e. a null record with an access discriminant) turns right back
> into a problem of an array of indefinite types.  I can always declare a
> procedure that takes a bunch of individual parameters, but this seems like a
> kludge, and doesn't solve the problem if the number of items might vary.  It
> would be nice if there was some way to establish that a discriminated record
> is in fact a fixed size, or perhaps if an array of anonymous access types had
> the same accessibility as access discriminants.  But if anyone knows of a
> workaround, I would be interested in how it was done.

How about an indefinite container?

-- 
Jeff Carter
"I feel as though somebody stepped on my tongue
with muddy feet."
Never Give a Sucker an Even Break
112



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

* Re: Passing indefinite types
  2013-02-02 21:31 ` Jeffrey Carter
@ 2013-02-03  0:27   ` sbelmont700
  2013-02-03  8:07     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 12+ messages in thread
From: sbelmont700 @ 2013-02-03  0:27 UTC (permalink / raw)


On Saturday, February 2, 2013 4:31:06 PM UTC-5, Jeffrey Carter wrote:
> 
> How about an indefinite container?
> 

I had considered it, but that only works for non-limited types, and, ultimately, uses the heap.

-sb



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

* Re: Passing indefinite types
  2013-02-03  0:27   ` sbelmont700
@ 2013-02-03  8:07     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2013-02-03  8:07 UTC (permalink / raw)


On Sat, 2 Feb 2013 16:27:32 -0800 (PST), sbelmont700@gmail.com wrote:

> On Saturday, February 2, 2013 4:31:06 PM UTC-5, Jeffrey Carter wrote:
>> 
>> How about an indefinite container?
> 
> I had considered it, but that only works for non-limited types, and, ultimately, uses the heap.

A custom storage pool then? Sometimes I am using stack or pool
mark-and-release pools. That would mean access types of course.

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



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

* Re: Passing indefinite types
  2013-02-02 21:07 Passing indefinite types sbelmont700
  2013-02-02 21:31 ` Jeffrey Carter
@ 2013-02-03 10:22 ` gautier_niouzes
  2013-02-03 22:26 ` Stephen Leake
  2013-02-05 21:16 ` sbelmont700
  3 siblings, 0 replies; 12+ messages in thread
From: gautier_niouzes @ 2013-02-03 10:22 UTC (permalink / raw)


Hello,
Perhaps an ad-hoc, in-memory stream would fit your needs ?
HTH
_________________________ 
Gautier's Ada programming 
http://sf.net/users/gdemont



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

* Re: Passing indefinite types
  2013-02-02 21:07 Passing indefinite types sbelmont700
  2013-02-02 21:31 ` Jeffrey Carter
  2013-02-03 10:22 ` gautier_niouzes
@ 2013-02-03 22:26 ` Stephen Leake
  2013-02-04  1:25   ` sbelmont700
  2013-02-05 21:16 ` sbelmont700
  3 siblings, 1 reply; 12+ messages in thread
From: Stephen Leake @ 2013-02-03 22:26 UTC (permalink / raw)


sbelmont700@gmail.com writes:

> Does anyone know of a slick way to pass several locally declared,
> indefinite types to a subprogram without resorting to the heap or
> Unchecked_Access? 

Could you show some almost legal code?

> An array of indefinite types is obviously not possible, an array of
> named access types is subject to accessibility problems, and wrapping
> the object in an 'accessor' (i.e. a null record with an access
> discriminant) turns right back into a problem of an array of
> indefinite types. I can always declare a procedure that takes a bunch
> of individual parameters, but this seems like a kludge, and doesn't
> solve the problem if the number of items might vary. It would be nice
> if there was some way to establish that a discriminated record is in
> fact a fixed size, 

Is it fixed, or does it vary? you point out several solutions for fixed.

> or perhaps if an array of anonymous access types had the same
> accessibility as access discriminants. 

I gather the subprogram you are calling is at library level, or at least
at a less deep accessibility level than the objects? While the local
objects are on the stack. 

How is the subprogram declared? If it takes several parameters each of
different indefinite type, then you are fine. If it takes a record of
indefinite types, then they all must be access types, and
Unchecked_Acess is ok, as long as the subprogram promises not to copy
the pointer.

I wonder if it would be possible to write an aspect or other constraint
that asserts "no pointers are copied"?

-- 
-- Stephe



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

* Re: Passing indefinite types
  2013-02-03 22:26 ` Stephen Leake
@ 2013-02-04  1:25   ` sbelmont700
  2013-02-04  3:46     ` Shark8
                       ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: sbelmont700 @ 2013-02-04  1:25 UTC (permalink / raw)


On Sunday, February 3, 2013 5:26:15 PM UTC-5, Stephen Leake wrote:
> 
> Could you show some almost legal code?
> 

I have found several occasions where this is useful (mostly for dealing with classwide types in constructing functions), but for an example consider something more straightforward:  Suppose you want to write a subprogram that searches for a string pattern within an unconstrained number of other strings (and also suppose for the sake of argument that you cannot implement it as multiple calls to a subprogram that searches within a single string).  Since you can't have "ragged" arrays of indefinite types, you try an array of pointers:

package k
  type p is access all string;
  type a is array (positive range <>) of p;
  function find (p: string, sources : a) return boolean;
end k;

But you can't ever call this from a subprogram with locally declared strings, since trying to create p.a with local strings fails the accessibility check.  You can use heap values or unchecked_access, but that's ugly and ought to be unecessary, since the subprogram is not doing anything sketchy with the values.

You can't have an unconstrained number of access discriminants (or access parameters), and trying to 'wrap' each local value fails as well:

package k
  type p (s : access string) is null record;
  type a is array (positive range <>) of p;  --illegal!
  function find (p: string, sources : a) return boolean;
end k;

This is the most aggrevating, because p (in this case) is not actually indefinite, and is always a single, fixed-size (coextensions notwithstanding, but I don't dare look down that rabbit hole).

Even when the number is fixed, but sufficiently large, normal parameters are unwieldly.  For instance:

function find (p: string, source1 : string;
                          source2 : string;
                          <snip>
                          source451 : string) return boolean;
 
> 
> I wonder if it would be possible to write an aspect or other constraint
> 
> that asserts "no pointers are copied"?
> 

That's what access discriminats (and to a lesser extent, access parameters) usually work well for, but I suppose there is no way to create an unconstrained number of them.  What I would like to see is an aspect that says "this discriminated record is not going to be variant, so it's okay to nest it within records and arrays", so that arrays of 'accessors' are legal.

Thank you (everyone) for the responses.

-sb



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

* Re: Passing indefinite types
  2013-02-04  1:25   ` sbelmont700
@ 2013-02-04  3:46     ` Shark8
  2013-02-05  2:40     ` Randy Brukardt
  2013-02-05 13:01     ` Stephen Leake
  2 siblings, 0 replies; 12+ messages in thread
From: Shark8 @ 2013-02-04  3:46 UTC (permalink / raw)


On Sunday, February 3, 2013 7:25:39 PM UTC-6, sbelm...@gmail.com wrote:
> 
> That's what access discriminats (and to a lesser extent, access parameters) usually work well for, but I suppose there is no way to create an unconstrained number of them.  What I would like to see is an aspect that says "this discriminated record is not going to be variant, so it's okay to nest it within records and arrays", so that arrays of 'accessors' are legal.
> 
> Thank you (everyone) for the responses.

What about structuring your generic to take a [definite] private type as its parameter (and array thereof), then create a record-wrapper (a single field, that being your access-type) (with an accessor-function), then pass an array of those records?



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

* Re: Passing indefinite types
  2013-02-04  1:25   ` sbelmont700
  2013-02-04  3:46     ` Shark8
@ 2013-02-05  2:40     ` Randy Brukardt
  2013-02-05 13:01     ` Stephen Leake
  2 siblings, 0 replies; 12+ messages in thread
From: Randy Brukardt @ 2013-02-05  2:40 UTC (permalink / raw)


<sbelmont700@gmail.com> wrote in message 
news:8d39b2ad-dc6c-4492-bc43-d2d01d748efa@googlegroups.com...
On Sunday, February 3, 2013 5:26:15 PM UTC-5, Stephen Leake wrote:
>>
>> Could you show some almost legal code?
>
>I have found several occasions where this is useful (mostly for dealing 
>with classwide types
>in constructing functions), but for an example consider something more 
>straightforward:
>Suppose you want to write a subprogram that searches for a string pattern 
>within an
>unconstrained number of other strings (and also suppose for the sake of 
>argument that
>you cannot implement it as multiple calls to a subprogram that searches 
>within a single string).

For this particular example, you ought to use an array of unbounded strings 
(or, if heap use has to be completely avoided, an array of bounded strings). 
QED. :-)

The clear analog of this is either an array of holder containers, or a 
vector of indefinite items. I realize both of these use the heap, but really 
that shouldn't be a concern until/unless it is proven to be an issue. 
(Trying to avoid it initially is almost always premature optimization.)

It hard to imagine doing too much with indefinite objects without resorting 
to the heap (or containers that use the heap) at some point. That's true for 
not just this problem, but pretty much any problem. The main reason to avoid 
heap use is worries about botched memory management, but that shouldn't be a 
concern if you use a predefined container or type like unbounded strings. If 
you truly need to avoid the heap (as per some embedded systems), I suspect 
you'll be forced to avoid indefinite types, too (other than as parameters as 
in class-wide or unconstrained array parameters).

Just my 5 cents.

                            Randy.





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

* Re: Passing indefinite types
  2013-02-04  1:25   ` sbelmont700
  2013-02-04  3:46     ` Shark8
  2013-02-05  2:40     ` Randy Brukardt
@ 2013-02-05 13:01     ` Stephen Leake
  2013-02-05 20:56       ` Randy Brukardt
  2 siblings, 1 reply; 12+ messages in thread
From: Stephen Leake @ 2013-02-05 13:01 UTC (permalink / raw)


sbelmont700@gmail.com writes:

> On Sunday, February 3, 2013 5:26:15 PM UTC-5, Stephen Leake wrote:
>> 
>> Could you show some almost legal code?
>> 
>
> package k
>   type p is access all string;
>   type a is array (positive range <>) of p;
>   function find (p: string, sources : a) return boolean;
> end k;
>
> But you can't ever call this from a subprogram with locally declared
> strings, since trying to create p.a with local strings fails the
> accessibility check.  

Just to be complete:

package k is
  type p is access all string;
  type a is array (positive range <>) of p;
  function find (p: string; sources : a) return boolean;
end k;

with Ada.Text_IO; use Ada.Text_IO;
with K;
procedure Try_K
is
   String_1 : aliased String := "Hello";
   String_2 : aliased String := "There";
   Sources : constant K.A := (String_1'Access, String_2'Access);
begin
   Put_Line ("Find => " & Boolean'Image (K.Find ("There", Sources)) );
end Try_K;

try_k.adb:7:31: non-local pointer cannot point to local object
try_k.adb:7:48: non-local pointer cannot point to local object

>You can use heap values or unchecked_access, but that's ugly and ought
>to be unecessary, since the subprogram is not doing anything sketchy
>with the values.

So you are looking for a way to have a collection of ragged, statically
declared strings. In C you can do this, with essentially the same code
as above, but the C compiler doesn't complain about accessibility.

In Ada you can do this with a container, but that does involve the heap.
I think the standard response here is "worrying about the heap is
premature optimization". Unless of course you are using Ravenscar or
some other target, that doesn't have a heap :).

> This is the most aggrevating, because p (in this case) is not actually
> indefinite, and is always a single, fixed-size

In that case, you _can_ have an array of static strings:

package k2 is
  subtype p is String (1 .. 5);
  type a is array (positive range <>) of p;
  function find (p: string; sources : a) return boolean;
end k2;

package k2 is
  subtype p is String (1 .. 5);
  type a is array (positive range <>) of p;
  function find (p: string; sources : a) return boolean;
end k2;

package body k2 is
   function find (p: string; sources : a) return boolean is
   begin
      for I of Sources loop
         if P = I then
            return True;
         end if;
      end loop;
      return False;
   end find;
end k2;

./try_k2.exe 
Find => TRUE


If you need different values for p'last, use a generic.

>> I wonder if it would be possible to write an aspect or other constraint
>> that asserts "no pointers are copied"?

> That's what access discriminats (and to a lesser extent, access
> parameters) usually work well for, but I suppose there is no way to
> create an unconstrained number of them. What I would like to see is an
> aspect that says "this discriminated record is not going to be
> variant, so it's okay to nest it within records and arrays", so that
> arrays of 'accessors' are legal.

You are missing my point. The reason the compiler doesn't like the first
solution above is that it assumes 'find' might copy the pointers in
'sources'. So if you can add an aspect to find:

  function find (p: string; sources : a) return boolean
    with Does_Not_Copy_Access_Values => True;

Then the compiler could eliminate the accessibility check, and the first
approach would be legal.

GNAT 7.1.0w doesn't like this, because Does_Not_Copy_Access_Values is
not a predefined aspect. So this is the beginnings of a proposed
addition to Ada 202x.

I tried using Suppress:

   pragma Suppress (Accessibility_Check, String_1);
   pragma Suppress (Accessibility_Check, Sources);
   pragma Suppress (Accessibility_Check, A);

None of those helped; I'm not clear why not. Possibly because the
failure is a legality issue, not a run-time check issue.

-- 
-- Stephe



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

* Re: Passing indefinite types
  2013-02-05 13:01     ` Stephen Leake
@ 2013-02-05 20:56       ` Randy Brukardt
  0 siblings, 0 replies; 12+ messages in thread
From: Randy Brukardt @ 2013-02-05 20:56 UTC (permalink / raw)


"Stephen Leake" <stephen_leake@stephe-leake.org> wrote in message 
news:85r4ku52zz.fsf@stephe-leake.org...
...
> I tried using Suppress:
>
>   pragma Suppress (Accessibility_Check, String_1);
>   pragma Suppress (Accessibility_Check, Sources);
>   pragma Suppress (Accessibility_Check, A);
>
> None of those helped; I'm not clear why not. Possibly because the
> failure is a legality issue, not a run-time check issue.

Correct: accessibility is a legality check in most cases. You could force it 
to be a dynamic check by using an anonynous-access-to-object type, and then 
you might be able to suppress the check (that's implementation-defined, of 
course, compilers are always allowed to make a check). Alternatively, just 
use 'Unchecked_Access and there is no accessibility check. (Of course, 
you're on your own at that point.)

                             Randy.





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

* Re: Passing indefinite types
  2013-02-02 21:07 Passing indefinite types sbelmont700
                   ` (2 preceding siblings ...)
  2013-02-03 22:26 ` Stephen Leake
@ 2013-02-05 21:16 ` sbelmont700
  3 siblings, 0 replies; 12+ messages in thread
From: sbelmont700 @ 2013-02-05 21:16 UTC (permalink / raw)



I had pretty much resigned myself to using the heap anyhow, this was mostly just out of curiosity as to whether it could be done or not.  It seems a shame that it cannot, since there are already mechanisms to safely pass local access values to longer-lived subprograms, so long as their are by themselves or within records.  An array seems like the logical next step.

But in the interests of proving it can actually be done, here is my best take on it: a (completly unreadable) linked list of access-discriminanted records, where the callee would presumably iterate through them as needed.  This would work for limited types, too, whereas (most of?) the normal containers would not.


package k is

   type String_Holder (s : not null access string) is null record;
   
   type Node;
   type Node_Holder (n : not null access Node) is null record;

   type Node (string_data : not null access String_Holder;
              next_node   : access Node_Holder) is null record;
              
   function find (pattern : string;
                  sources : Node) return boolean;
                   
end k;

procedure p is

  s1   : aliased string := "One thing";
  s2   : aliased string := "another thing";
  s3   : aliased string := "third thing";
  
  s1_h : aliased k.string_holder := (s => s1'access);
  s2_h : aliased k.string_holder := (s => s2'access);
  s3_h : aliased k.string_holder := (s => s3'access);

  n3   : aliased k.node := (s3_h'access, null);
  n3_h : aliased k.node_holder := (n => n3'access);
  
  n2   : aliased k.node := (s2_h'access, n3_h'access);
  n2_h : aliased k.node_holder := (n => n2'access);
  
  n1   : k.node := (s1_h'access, n2_h'access);
  
  x : boolean := k.find ("look ma, no heap!", n1);

begin
  null;
end;

Thanks again to everyone for their suggestions.

-sb



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

end of thread, other threads:[~2013-02-05 21:16 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-02 21:07 Passing indefinite types sbelmont700
2013-02-02 21:31 ` Jeffrey Carter
2013-02-03  0:27   ` sbelmont700
2013-02-03  8:07     ` Dmitry A. Kazakov
2013-02-03 10:22 ` gautier_niouzes
2013-02-03 22:26 ` Stephen Leake
2013-02-04  1:25   ` sbelmont700
2013-02-04  3:46     ` Shark8
2013-02-05  2:40     ` Randy Brukardt
2013-02-05 13:01     ` Stephen Leake
2013-02-05 20:56       ` Randy Brukardt
2013-02-05 21:16 ` sbelmont700

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