comp.lang.ada
 help / color / mirror / Atom feed
* Address of an object
@ 2006-09-15 20:24 Dmitry A. Kazakov
  2006-09-15 23:31 ` Adam Beneschan
  2006-09-16 13:21 ` Stephen Leake
  0 siblings, 2 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2006-09-15 20:24 UTC (permalink / raw)


Both X'Address and Unchecked_Conversion of a pointer to X would not give
the true address of X (i.e. the address returned by Allocate of the
corresponding storage pool). For an array type, X'Address is the address of
the first element, the dope is out.

Is there any better way than this extremely ugly and slow:

   type Fake_Pool is new Root_Storage_Pool with record
      Location : Address;
   end record;

   procedure Allocate (...) is -- Never called
   begin
      raise Program_Error;
   end Allocate;

   procedure Deallocate
             (  Pool            : in out Fake_Pool; 
                Storage_Address : in Address; 
                Size            : Storage_Count;
                Alignment       : Storage_Count
             )  is
   begin
      Pool.Location := Storage_Address;
   end Deallocate;

   function Storage_Size (Pool : Fake_Pool) -- Never called
      return Storage_Count is
   begin
      return 0;
   end Storage_Size;

   function Address_Of (Pointer : Object_Ptr) return Address is
      Pool : Fake_Pool; -- A controlled object, that must be slow!
      type Fake_Ptr is access Object_Type;
      for Fake_Ptr'Storage_Pool use Pool;
      function To_Fake is
         new Ada.Unchecked_Conversion (Object_Ptr, Fake_Ptr);
      procedure Free is
         new Ada.Unchecked_Deallocation (Object_Type, Fake_Ptr);
      Ptr : Fake_Ptr := To_Fake (Pointer);
   begin
      Free (Ptr);
      return Pool.Location;
   end Address_Of;

?

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



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

* Re: Address of an object
  2006-09-15 20:24 Address of an object Dmitry A. Kazakov
@ 2006-09-15 23:31 ` Adam Beneschan
  2006-09-16  8:13   ` Dmitry A. Kazakov
  2006-09-16 13:21 ` Stephen Leake
  1 sibling, 1 reply; 12+ messages in thread
From: Adam Beneschan @ 2006-09-15 23:31 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> Both X'Address and Unchecked_Conversion of a pointer to X would not give
> the true address of X (i.e. the address returned by Allocate of the
> corresponding storage pool). For an array type, X'Address is the address of
> the first element, the dope is out.
>
> Is there any better way than this extremely ugly and slow:
>
>    type Fake_Pool is new Root_Storage_Pool with record
>       Location : Address;
>    end record;
>
>    procedure Allocate (...) is -- Never called
>    begin
>       raise Program_Error;
>    end Allocate;
>
>    procedure Deallocate
>              (  Pool            : in out Fake_Pool;
>                 Storage_Address : in Address;
>                 Size            : Storage_Count;
>                 Alignment       : Storage_Count
>              )  is
>    begin
>       Pool.Location := Storage_Address;
>    end Deallocate;
>
>    function Storage_Size (Pool : Fake_Pool) -- Never called
>       return Storage_Count is
>    begin
>       return 0;
>    end Storage_Size;
>
>    function Address_Of (Pointer : Object_Ptr) return Address is
>       Pool : Fake_Pool; -- A controlled object, that must be slow!
>       type Fake_Ptr is access Object_Type;
>       for Fake_Ptr'Storage_Pool use Pool;
>       function To_Fake is
>          new Ada.Unchecked_Conversion (Object_Ptr, Fake_Ptr);
>       procedure Free is
>          new Ada.Unchecked_Deallocation (Object_Type, Fake_Ptr);
>       Ptr : Fake_Ptr := To_Fake (Pointer);
>    begin
>       Free (Ptr);
>       return Pool.Location;
>    end Address_Of;
>
> ?

This sounds highly implementation-dependent.  I don't know what an
Object_Ptr points to; but if it points to something that could be
represented, in some implementations, as discontiguous data, then the
above won't necessarily work---calling the instance of
Unchecked_Deallocation could well cause the storage pool Deallocate
routine to be called more than once.  And then your result will be
whatever was passed to the last Deallocate call, which may or may not
be meaningful.

I don't think there's an implementation-independent way to get what
you're looking for (and, frankly, I'm not even sure there's an
implementation-independent way to *define* what you're looking for).
Assuming that you're interested in only one implementation, perhaps you
can ask the implementors to provide an implementation-dependent
attribute or something to give you what you need.

                                     -- Adam




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

* Re: Address of an object
  2006-09-15 23:31 ` Adam Beneschan
@ 2006-09-16  8:13   ` Dmitry A. Kazakov
  2006-09-18 10:29     ` Stephen Leake
  0 siblings, 1 reply; 12+ messages in thread
From: Dmitry A. Kazakov @ 2006-09-16  8:13 UTC (permalink / raw)


On 15 Sep 2006 16:31:54 -0700, Adam Beneschan wrote:

> Dmitry A. Kazakov wrote:
>> Both X'Address and Unchecked_Conversion of a pointer to X would not give
>> the true address of X (i.e. the address returned by Allocate of the
>> corresponding storage pool). For an array type, X'Address is the address of
>> the first element, the dope is out.
>>
>> Is there any better way than this extremely ugly and slow:
>>
>>    type Fake_Pool is new Root_Storage_Pool with record
>>       Location : Address;
>>    end record;
>>
>>    procedure Allocate (...) is -- Never called
>>    begin
>>       raise Program_Error;
>>    end Allocate;
>>
>>    procedure Deallocate
>>              (  Pool            : in out Fake_Pool;
>>                 Storage_Address : in Address;
>>                 Size            : Storage_Count;
>>                 Alignment       : Storage_Count
>>              )  is
>>    begin
>>       Pool.Location := Storage_Address;
>>    end Deallocate;
>>
>>    function Storage_Size (Pool : Fake_Pool) -- Never called
>>       return Storage_Count is
>>    begin
>>       return 0;
>>    end Storage_Size;
>>
>>    function Address_Of (Pointer : Object_Ptr) return Address is
>>       Pool : Fake_Pool; -- A controlled object, that must be slow!
>>       type Fake_Ptr is access Object_Type;
>>       for Fake_Ptr'Storage_Pool use Pool;
>>       function To_Fake is
>>          new Ada.Unchecked_Conversion (Object_Ptr, Fake_Ptr);
>>       procedure Free is
>>          new Ada.Unchecked_Deallocation (Object_Type, Fake_Ptr);
>>       Ptr : Fake_Ptr := To_Fake (Pointer);
>>    begin
>>       Free (Ptr);
>>       return Pool.Location;
>>    end Address_Of;
>>
>> ?
> 
> This sounds highly implementation-dependent.

At best!

> I don't think there's an implementation-independent way to get what
> you're looking for (and, frankly, I'm not even sure there's an
> implementation-independent way to *define* what you're looking for).
> Assuming that you're interested in only one implementation, perhaps you
> can ask the implementors to provide an implementation-dependent
> attribute or something to give you what you need.

Hmm, actually it is quite easy to define formally:

Let P be a pointer to X. Then what I need is the address A, which the pool
P'Storage_Pool returned when X was allocated there. This is the same
address the pool will receive upon freeing X.

----------
The problem behind. What I need is to be able to add some dopes to the
objects allocated in *my* pool. new T calls to the pool's Allocate, but the
address it returns gets mangled by the compiler, when converted to the
pointer P [for example, when T is String]. So, having P I cannot get at my
dope. Its address should be

A = P.all'Address - Offs

where Offs is known, alas, to the compiler only. The compiler must know
that, otherwise it couldn't pass that to Deallocate.

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



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

* Re: Address of an object
  2006-09-15 20:24 Address of an object Dmitry A. Kazakov
  2006-09-15 23:31 ` Adam Beneschan
@ 2006-09-16 13:21 ` Stephen Leake
  2006-09-16 17:06   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 12+ messages in thread
From: Stephen Leake @ 2006-09-16 13:21 UTC (permalink / raw)


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

> Both X'Address and Unchecked_Conversion of a pointer to X would not give
> the true address of X (i.e. the address returned by Allocate of the
> corresponding storage pool). For an array type, X'Address is the address of
> the first element, the dope is out.
>
> Is there any better way 

A better way to do what?

What are you doing, that either X'Address or X'Access is wrong?

-- 
-- Stephe



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

* Re: Address of an object
  2006-09-16 13:21 ` Stephen Leake
@ 2006-09-16 17:06   ` Dmitry A. Kazakov
  2006-09-20  0:43     ` Randy Brukardt
  0 siblings, 1 reply; 12+ messages in thread
From: Dmitry A. Kazakov @ 2006-09-16 17:06 UTC (permalink / raw)


On Sat, 16 Sep 2006 09:21:51 -0400, Stephen Leake wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> Both X'Address and Unchecked_Conversion of a pointer to X would not give
>> the true address of X (i.e. the address returned by Allocate of the
>> corresponding storage pool). For an array type, X'Address is the address of
>> the first element, the dope is out.
>>
>> Is there any better way 
> 
> A better way to do what?
> 
> What are you doing, that either X'Address or X'Access is wrong?

Both are. Do the following under GNAT:

type P is access String;
for P'Storage_Pool use My_Pool;

procedure Allocate (Pool : My_Pool; Addr : out Storage_Address; ...) is
begin
   ...
   Addr := A;
end Allocate;

P := new String'("abc");

Then compare A with P.all'Address. They will differ. A = P.all'Address - 8,
I guess. [ It is not yet another bug of GNAT, it is a proper behavior. ARM
explicitly requires this.]

See also my response to Adam.

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



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

* Re: Address of an object
  2006-09-16  8:13   ` Dmitry A. Kazakov
@ 2006-09-18 10:29     ` Stephen Leake
  2006-09-18 12:09       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 12+ messages in thread
From: Stephen Leake @ 2006-09-18 10:29 UTC (permalink / raw)


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

> Let P be a pointer to X. Then what I need is the address A, which the pool
> P'Storage_Pool returned when X was allocated there. This is the same
> address the pool will receive upon freeing X.
>
> ----------
> The problem behind. What I need is to be able to add some dopes to the
> objects allocated in *my* pool. new T calls to the pool's Allocate, but the
> address it returns gets mangled by the compiler, when converted to the
> pointer P [for example, when T is String]. So, having P I cannot get at my
> dope. Its address should be
>
> A = P.all'Address - Offs
>
> where Offs is known, alas, to the compiler only. The compiler must know
> that, otherwise it couldn't pass that to Deallocate.

So you want access to some compiler-dependent information; clearly the
method will be compiler-dependent, since it isn't defined by the language.

What are you going to do with the "dopes" you add? They won't be
visible from Ada.

-- 
-- Stephe



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

* Re: Address of an object
  2006-09-18 10:29     ` Stephen Leake
@ 2006-09-18 12:09       ` Dmitry A. Kazakov
  2006-09-18 13:54         ` Maciej Sobczak
  2006-09-19  9:15         ` Stephen Leake
  0 siblings, 2 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2006-09-18 12:09 UTC (permalink / raw)


On Mon, 18 Sep 2006 06:29:24 -0400, Stephen Leake wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> Let P be a pointer to X. Then what I need is the address A, which the pool
>> P'Storage_Pool returned when X was allocated there. This is the same
>> address the pool will receive upon freeing X.
>>
>> ----------
>> The problem behind. What I need is to be able to add some dopes to the
>> objects allocated in *my* pool. new T calls to the pool's Allocate, but the
>> address it returns gets mangled by the compiler, when converted to the
>> pointer P [for example, when T is String]. So, having P I cannot get at my
>> dope. Its address should be
>>
>> A = P.all'Address - Offs
>>
>> where Offs is known, alas, to the compiler only. The compiler must know
>> that, otherwise it couldn't pass that to Deallocate.
> 
> So you want access to some compiler-dependent information; clearly the
> method will be compiler-dependent, since it isn't defined by the language.

No, I don't want to access it. I only want my information.

> What are you going to do with the "dopes" you add? They won't be
> visible from Ada.

That's exactly the goal, because what I want is to extend types in a way
Ada does not support. I wanted to add something to a type without
quarreling with Ada, which mistakenly [OK, that was a political decision]
does not support MI. It was corrected in Ada 2005 but only for pure
interfaces, while I need implementations. There is a vast number of cases
where it might be useful.

It seemed quite easy, thank to user-defined pools. Well, actually it is
spoiled a bit with pointers and generics, but that's another story. The
idea is as follows:

1. You define a pool which eventually takes its memory from some another
pool.

2. When something is allocated in the pool, you just add necessary data to
the allocated object in front of the allocated memory block

3. The interface to this is a generic package, which provides a pointer
type to the objects in the pool. [Unfortunately, the type of the pointer's
pool cannot be made opaque, but that is a minor language problem.]

4. New operations are defined on the pointer type.

It is clean and portable design, because all the functionality is hidden
behind the pointer type. It does not break the type allocated in the pool
in any way.

The only unexpected problem with this is that the compiler mangles pointers
and there seems to be no way to influence or learn how it does this.

I would suggest to introduce a new attribute X'Pool_Address which should
return the address, Unchecked_Deallocation would pass to Deallocate, but...

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



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

* Re: Address of an object
  2006-09-18 12:09       ` Dmitry A. Kazakov
@ 2006-09-18 13:54         ` Maciej Sobczak
  2006-09-18 14:53           ` Dmitry A. Kazakov
  2006-09-19  9:15         ` Stephen Leake
  1 sibling, 1 reply; 12+ messages in thread
From: Maciej Sobczak @ 2006-09-18 13:54 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> I wanted to add something to a type without
> quarreling with Ada, which mistakenly [OK, that was a political decision]
> does not support MI.


You might consider doing it in C++ instead.

Because - you know - *fighting with the language* can only increase the 
probability of introducing bugs and in the end increase the total cost 
of software production, not mentioning its maintenance.

(Sorry, could not resist. ;-) )


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



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

* Re: Address of an object
  2006-09-18 13:54         ` Maciej Sobczak
@ 2006-09-18 14:53           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2006-09-18 14:53 UTC (permalink / raw)


On Mon, 18 Sep 2006 15:54:30 +0200, Maciej Sobczak wrote:

> Dmitry A. Kazakov wrote:
> 
>> I wanted to add something to a type without
>> quarreling with Ada, which mistakenly [OK, that was a political decision]
>> does not support MI.
> 
> You might consider doing it in C++ instead.

Actually, I did. It was long ago. OK, there were other problems with that
in C++. But for all, the project is in Ada.

> Because - you know - *fighting with the language* can only increase the 
> probability of introducing bugs and in the end increase the total cost 
> of software production, not mentioning its maintenance.

That's true. But we should consider all causes where we are forced to fight
with the language.

And the problem with C++ is that it is almost impossible to cut a clean
design of anything by an inch more complex than hello-world...

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



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

* Re: Address of an object
  2006-09-18 12:09       ` Dmitry A. Kazakov
  2006-09-18 13:54         ` Maciej Sobczak
@ 2006-09-19  9:15         ` Stephen Leake
  2006-09-19 13:29           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 12+ messages in thread
From: Stephen Leake @ 2006-09-19  9:15 UTC (permalink / raw)


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

>> So you want access to some compiler-dependent information; clearly the
>> method will be compiler-dependent, since it isn't defined by the language.
>
> No, I don't want to access it. I only want my information.

I don't understand. You want write-only data?

>> What are you going to do with the "dopes" you add? They won't be
>> visible from Ada.
>
> That's exactly the goal, because what I want is to extend types in a way
> Ada does not support. I wanted to add something to a type without
> quarreling with Ada, which mistakenly [OK, that was a political decision]
> does not support MI. It was corrected in Ada 2005 but only for pure
> interfaces, while I need implementations. There is a vast number of cases
> where it might be useful.

So you are trying to extend the Ada language. You should be editing
the compiler; that's one of the reasons GNAT is open source.

> It seemed quite easy, thank to user-defined pools. Well, actually it is
> spoiled a bit with pointers and generics, but that's another story. 

Actually, that's part of the reason MI isn't in Ada. You must consider
how it impacts the entire language.

> The idea is as follows:
>
> 1. You define a pool which eventually takes its memory from some another
> pool.
>
> 2. When something is allocated in the pool, you just add necessary data to
> the allocated object in front of the allocated memory block
>
> 3. The interface to this is a generic package, which provides a pointer
> type to the objects in the pool. [Unfortunately, the type of the pointer's
> pool cannot be made opaque, but that is a minor language problem.]

So this generic package needs to read the data, from Ada. Or at least
provide a pointer to it, so other Ada packages can read it.

> 4. New operations are defined on the pointer type.

In Ada, or some other language?

> It is clean and portable design, because all the functionality is hidden
> behind the pointer type. It does not break the type allocated in the pool
> in any way.
>
> The only unexpected problem with this is that the compiler mangles pointers
> and there seems to be no way to influence or learn how it does this.

Read the source code for the compiler. Or ask the compiler vendor.

-- 
-- Stephe



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

* Re: Address of an object
  2006-09-19  9:15         ` Stephen Leake
@ 2006-09-19 13:29           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2006-09-19 13:29 UTC (permalink / raw)


On Tue, 19 Sep 2006 05:15:01 -0400, Stephen Leake wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>>> So you want access to some compiler-dependent information; clearly the
>>> method will be compiler-dependent, since it isn't defined by the language.
>>
>> No, I don't want to access it. I only want my information.
> 
> I don't understand. You want write-only data?

No, I just don't care about them. As an example consider a container
library or a garbage collector. They don't care about handling the data.

>>> What are you going to do with the "dopes" you add? They won't be
>>> visible from Ada.
>>
>> That's exactly the goal, because what I want is to extend types in a way
>> Ada does not support. I wanted to add something to a type without
>> quarreling with Ada, which mistakenly [OK, that was a political decision]
>> does not support MI. It was corrected in Ada 2005 but only for pure
>> interfaces, while I need implementations. There is a vast number of cases
>> where it might be useful.
> 
> So you are trying to extend the Ada language. You should be editing
> the compiler; that's one of the reasons GNAT is open source.

GNAT is, but Ada isn't. For extending Ada there are AIs. 

>> It seemed quite easy, thank to user-defined pools. Well, actually it is
>> spoiled a bit with pointers and generics, but that's another story. 
> 
> Actually, that's part of the reason MI isn't in Ada. You must consider
> how it impacts the entire language.

There cannot be any negative impact. Fundamentally, if MI is infeasible,
then single inheritance must be as well. Once Ada has decided to support
inheritance there is no return.

>> The idea is as follows:
>>
>> 1. You define a pool which eventually takes its memory from some another
>> pool.
>>
>> 2. When something is allocated in the pool, you just add necessary data to
>> the allocated object in front of the allocated memory block
>>
>> 3. The interface to this is a generic package, which provides a pointer
>> type to the objects in the pool. [Unfortunately, the type of the pointer's
>> pool cannot be made opaque, but that is a minor language problem.]
> 
> So this generic package needs to read the data, from Ada. Or at least
> provide a pointer to it, so other Ada packages can read it.

Sure. The pointer is a legal access type, you can do with it and through it
anything, one could do in Ada.

>> 4. New operations are defined on the pointer type.
> 
> In Ada, or some other language?

Of course in Ada. OK, I feel there is a need to give an example. I will
start a new thread for it.

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



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

* Re: Address of an object
  2006-09-16 17:06   ` Dmitry A. Kazakov
@ 2006-09-20  0:43     ` Randy Brukardt
  0 siblings, 0 replies; 12+ messages in thread
From: Randy Brukardt @ 2006-09-20  0:43 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:n03kqae9v6ah$.hjxa120hu8oq$.dlg@40tude.net...
...
> type P is access String;
> for P'Storage_Pool use My_Pool;
>
> procedure Allocate (Pool : My_Pool; Addr : out Storage_Address; ...) is
> begin
>    ...
>    Addr := A;
> end Allocate;
>
> P := new String'("abc");
>
> Then compare A with P.all'Address. They will differ. A = P.all'Address -
8,
> I guess. [ It is not yet another bug of GNAT, it is a proper behavior. ARM
> explicitly requires this.]

For what it's worth, Janus/Ada does this right (currently -- I suppose
someday we might change it to match the RM, but it is unlikely -- we'd have
to ban address clauses of any object with discontiguous parts, which is
silly). I argued against this change to 'Address in Ada 95, but I seem to
have been a minority of 1 -- so it's nice to see someone else who cares.

                               Randy.





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

end of thread, other threads:[~2006-09-20  0:43 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-09-15 20:24 Address of an object Dmitry A. Kazakov
2006-09-15 23:31 ` Adam Beneschan
2006-09-16  8:13   ` Dmitry A. Kazakov
2006-09-18 10:29     ` Stephen Leake
2006-09-18 12:09       ` Dmitry A. Kazakov
2006-09-18 13:54         ` Maciej Sobczak
2006-09-18 14:53           ` Dmitry A. Kazakov
2006-09-19  9:15         ` Stephen Leake
2006-09-19 13:29           ` Dmitry A. Kazakov
2006-09-16 13:21 ` Stephen Leake
2006-09-16 17:06   ` Dmitry A. Kazakov
2006-09-20  0:43     ` Randy Brukardt

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