* On absurdity of collections 7.6.1 (11.1/3) @ 2021-09-29 9:09 Dmitry A. Kazakov 2021-09-29 11:05 ` Simon Wright 2021-09-30 18:23 ` G.B. 0 siblings, 2 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-09-29 9:09 UTC (permalink / raw) For Ada programmers who wonder what it is, here is a practical example. Given the package specification: package P is type Item (Length : Positive) is new Ada.Finalization.Limited_Controlled with record Text : String (1..Length); end record; overriding procedure Finalize (X : in out Item); type Item_Ptr is access all Item; function New_Item ( Pool : in out Root_Storage_Pool'Class; Text : String ) return Item_Ptr; procedure Free is new Ada.Unchecked_Deallocation (Item, Item_Ptr); end P; and the program using it like this: Ptr : Item_Ptr := New_Item (Some_Pool, "A"); ... Free (Ptr); Write the package body. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-29 9:09 On absurdity of collections 7.6.1 (11.1/3) Dmitry A. Kazakov @ 2021-09-29 11:05 ` Simon Wright 2021-09-29 11:20 ` Dmitry A. Kazakov 2021-09-30 18:23 ` G.B. 1 sibling, 1 reply; 15+ messages in thread From: Simon Wright @ 2021-09-29 11:05 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > type Item_Ptr is access all Item; > function New_Item > ( Pool : in out Root_Storage_Pool'Class; > Text : String > ) return Item_Ptr; What I don't see is how you can implement this, never mind any other problems. 13.11(17) says "If Storage_Pool is not specified for a type defined by an access_to_object_definition, then the implementation chooses a standard storage pool for it in an implementation-defined manner." I see that 3.10(8) says "Access-to-object types are further subdivided into pool-specific access types [...] and general access types, whose values can designate the elements of any storage pool [...]" which implies that there *is* a mechanism. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-29 11:05 ` Simon Wright @ 2021-09-29 11:20 ` Dmitry A. Kazakov 2021-09-29 21:38 ` Simon Wright 2021-09-30 0:23 ` Randy Brukardt 0 siblings, 2 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-09-29 11:20 UTC (permalink / raw) On 2021-09-29 13:05, Simon Wright wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> type Item_Ptr is access all Item; >> function New_Item >> ( Pool : in out Root_Storage_Pool'Class; >> Text : String >> ) return Item_Ptr; > > What I don't see is how you can implement this, never mind any other > problems. A naive, but wrong due to 7.6.1 (11.1/3) nonsense, implementation would be: function New_Item ( Pool : in out Root_Storage_Pool'Class; Text : String ) return Item_Ptr is type Ptr is access Item; for Ptr'Storage_Pool use Pool; Object : Ptr := new Item (Text'Length); begin Object.Text := Text; return Object.all'Unchecked_Access; end New_Item; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-29 11:20 ` Dmitry A. Kazakov @ 2021-09-29 21:38 ` Simon Wright 2021-09-30 8:07 ` Dmitry A. Kazakov 2021-09-30 0:23 ` Randy Brukardt 1 sibling, 1 reply; 15+ messages in thread From: Simon Wright @ 2021-09-29 21:38 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On 2021-09-29 13:05, Simon Wright wrote: >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> >>> type Item_Ptr is access all Item; >>> function New_Item >>> ( Pool : in out Root_Storage_Pool'Class; >>> Text : String >>> ) return Item_Ptr; >> What I don't see is how you can implement this, never mind any other >> problems. > > A naive, but wrong due to 7.6.1 (11.1/3) nonsense, implementation would be: > > function New_Item > ( Pool : in out Root_Storage_Pool'Class; > Text : String > ) return Item_Ptr is > type Ptr is access Item; > for Ptr'Storage_Pool use Pool; > Object : Ptr := new Item (Text'Length); > begin > Object.Text := Text; > return Object.all'Unchecked_Access; > end New_Item; OK, that code compiles. What you'd need to happen when the returned Item_Ptr is freed would be for the mechanism of the actual pool to be invoked. But Item_Ptr was declared without any pool specified, so uses the default, and when the returned Item_Ptr is freed it uses the default pool's mechanism. But of course what actually happens with this code is that the returned Item_Ptr is left dangling; my test with P; with System.Pool_Local; -- GNAT special with Ada.Text_IO; use Ada.Text_IO; procedure Test is use P; Pool : System.Pool_Local.Unbounded_Reclaim_Pool; Ptr : Item_Ptr := New_Item (Pool, "hello"); begin Put_Line (Ptr.Text); Free (Ptr); end Test; manages flukily to print "hello" before crashing at the Free (Ptr). I don't see how what you want can be achieved without every access type containing a reference to the pool the object was allocated from. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-29 21:38 ` Simon Wright @ 2021-09-30 8:07 ` Dmitry A. Kazakov 2021-09-30 8:35 ` Simon Wright 2021-10-01 1:37 ` Randy Brukardt 0 siblings, 2 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-09-30 8:07 UTC (permalink / raw) On 2021-09-29 23:38, Simon Wright wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> On 2021-09-29 13:05, Simon Wright wrote: >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>> >>>> type Item_Ptr is access all Item; >>>> function New_Item >>>> ( Pool : in out Root_Storage_Pool'Class; >>>> Text : String >>>> ) return Item_Ptr; >>> What I don't see is how you can implement this, never mind any other >>> problems. >> >> A naive, but wrong due to 7.6.1 (11.1/3) nonsense, implementation would be: >> >> function New_Item >> ( Pool : in out Root_Storage_Pool'Class; >> Text : String >> ) return Item_Ptr is >> type Ptr is access Item; >> for Ptr'Storage_Pool use Pool; >> Object : Ptr := new Item (Text'Length); >> begin >> Object.Text := Text; >> return Object.all'Unchecked_Access; >> end New_Item; > > OK, that code compiles. > > What you'd need to happen when the returned Item_Ptr is freed would be > for the mechanism of the actual pool to be invoked. But Item_Ptr was > declared without any pool specified, so uses the default, and when the > returned Item_Ptr is freed it uses the default pool's mechanism. That would be another language bug, if true, because 13.11.2 is silent about that. But the first bug is that New_Item is not implementable, well it actually is, but in a very clumsy way (see my answer to Randy). > But of course what actually happens with this code is that the returned > Item_Ptr is left dangling; my test > > with P; > with System.Pool_Local; -- GNAT special > with Ada.Text_IO; use Ada.Text_IO; > procedure Test is > use P; > Pool : System.Pool_Local.Unbounded_Reclaim_Pool; > Ptr : Item_Ptr := New_Item (Pool, "hello"); > begin > Put_Line (Ptr.Text); > Free (Ptr); > end Test; > > manages flukily to print "hello" before crashing at the Free (Ptr). It should print it twice, because Finalize must be called twice. Once inside New_Item, then in Free. > I don't see how what you want can be achieved without every access type > containing a reference to the pool the object was allocated from. Yes, every general access type that permits instantiation of Unchecked_Dellocation must indicate the target object's pool, directly, e.g. per fat pointer, or indirectly by some other schema. I see nothing in RM that allows a different implementation. But it is could be a bug by omission and I am not a language lawyer anyway. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-30 8:07 ` Dmitry A. Kazakov @ 2021-09-30 8:35 ` Simon Wright 2021-09-30 8:49 ` Dmitry A. Kazakov 2021-10-01 1:37 ` Randy Brukardt 1 sibling, 1 reply; 15+ messages in thread From: Simon Wright @ 2021-09-30 8:35 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > It should print it twice, because Finalize must be called twice. Once > inside New_Item, then in Free. That's in your implementation of Finalize, which you haven't shown us ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-30 8:35 ` Simon Wright @ 2021-09-30 8:49 ` Dmitry A. Kazakov 0 siblings, 0 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-09-30 8:49 UTC (permalink / raw) On 2021-09-30 10:35, Simon Wright wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> It should print it twice, because Finalize must be called twice. Once >> inside New_Item, then in Free. > > That's in your implementation of Finalize, which you haven't shown us procedure Finalize (X : in out Item) is begin Put_Line (X.Text & " is dead"); end Finalize; P.S. You can use the standard pool: Ptr : Item_Ptr; type String_Ptr is access String; begin Ptr := New_Item (String_Ptr'Storage_Pool, "A"); Free (Ptr); -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-30 8:07 ` Dmitry A. Kazakov 2021-09-30 8:35 ` Simon Wright @ 2021-10-01 1:37 ` Randy Brukardt 2021-10-01 7:57 ` Dmitry A. Kazakov 1 sibling, 1 reply; 15+ messages in thread From: Randy Brukardt @ 2021-10-01 1:37 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:sj3r7l$pla$2@gioia.aioe.org... ... > Yes, every general access type that permits instantiation of > Unchecked_Dellocation must indicate the target object's pool, directly, > e.g. per fat pointer, or indirectly by some other schema. I see nothing in > RM that allows a different implementation. But it is could be a bug by > omission and I am not a language lawyer anyway. Each access type has only one pool, and all allocations and deallocations for that access type use that pool. You can see at RM 13.11(13) that you can retrieve the storage pool of T, that wouldn't be possible if it could have multiple pools. Allocation for T uses T'Storage_Pool (RM 13.11(16)), and deallocation for T also uses T'Storage_Pool (13.11.2(9/3) - I see this wording isn't as clear as it could be, but "the storage_pool" here is the one for the type T. It is clear, however, from 13.11.2(16/3) that it is erroneous to deallocate an object for some other pool than the pool of the access type passed to the instance of Unchecked_Deallocation. Surely no one would expect the pool to be associated with the object -- it would be impossible to interface to C or most other languages that way. Note that GNAT insists that all access types are C-compatible. As I've said repeatedly, if you want the behavior of multiple pools with a single access type, you have to use the subpool mechanism somehow. Randy. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-10-01 1:37 ` Randy Brukardt @ 2021-10-01 7:57 ` Dmitry A. Kazakov 0 siblings, 0 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-10-01 7:57 UTC (permalink / raw) On 2021-10-01 03:37, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:sj3r7l$pla$2@gioia.aioe.org... > ... >> Yes, every general access type that permits instantiation of >> Unchecked_Dellocation must indicate the target object's pool, directly, >> e.g. per fat pointer, or indirectly by some other schema. I see nothing in >> RM that allows a different implementation. But it is could be a bug by >> omission and I am not a language lawyer anyway. > > Each access type has only one pool, and all allocations and deallocations > for that access type use that pool. You can see at RM 13.11(13) that you can > retrieve the storage pool of T, that wouldn't be possible if it could have > multiple pools. Allocation for T uses T'Storage_Pool (RM 13.11(16)), and > deallocation for T also uses T'Storage_Pool (13.11.2(9/3) - I see this > wording isn't as clear as it could be, but "the storage_pool" here is the > one for the type T. It is clear, however, from 13.11.2(16/3) that it is > erroneous to deallocate an object for some other pool than the pool of the > access type passed to the instance of Unchecked_Deallocation. At least instantiations of Unchecked_Deallocation should be illegal with general access. > Surely no one would expect the pool to be associated with the object -- it > would be impossible to interface to C or most other languages that way. Note > that GNAT insists that all access types are C-compatible. Normally you cannot allocate C objects intended to be freed from C using Ada allocator. This is a common mistake of binding designers which promptly crashes the program. But I see no problem here, especially because the access type must have C convention anyway. > As I've said repeatedly, if you want the behavior of multiple pools with a > single access type, you have to use the subpool mechanism somehow. Honestly I still try to find a useful case for subpools. It is nothing that could not be easily implemented using existing pools or might help fighting off collections etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-29 11:20 ` Dmitry A. Kazakov 2021-09-29 21:38 ` Simon Wright @ 2021-09-30 0:23 ` Randy Brukardt 2021-09-30 8:06 ` Dmitry A. Kazakov 1 sibling, 1 reply; 15+ messages in thread From: Randy Brukardt @ 2021-09-30 0:23 UTC (permalink / raw) It's surely wrong, because you have to deallocate from the same pool as you allocated. And you have no way to save such a thing. There is no capability in Ada to use multiple pools with one access type. At best, you could directly call Allocate and Deallocate for this purpose, but it is impossible to use anything built-in. You could use the subpool mechanism (assuming you want a limited number of kinds of pools) to do this (each subpool could use a different allocation mechanism). But that would mean a giant pool type containing all of the implementations -- which seems suboptimal. Note that the subpool mechanism ensures that finalization happens when a subpool is destroyed. Randy. "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:sj1i6g$7hv$1@gioia.aioe.org... > On 2021-09-29 13:05, Simon Wright wrote: >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> >>> type Item_Ptr is access all Item; >>> function New_Item >>> ( Pool : in out Root_Storage_Pool'Class; >>> Text : String >>> ) return Item_Ptr; >> >> What I don't see is how you can implement this, never mind any other >> problems. > > A naive, but wrong due to 7.6.1 (11.1/3) nonsense, implementation would > be: > > function New_Item > ( Pool : in out Root_Storage_Pool'Class; > Text : String > ) return Item_Ptr is > type Ptr is access Item; > for Ptr'Storage_Pool use Pool; > Object : Ptr := new Item (Text'Length); > begin > Object.Text := Text; > return Object.all'Unchecked_Access; > end New_Item; > > -- > Regards, > Dmitry A. Kazakov > http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-30 0:23 ` Randy Brukardt @ 2021-09-30 8:06 ` Dmitry A. Kazakov 0 siblings, 0 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-09-30 8:06 UTC (permalink / raw) On 2021-09-30 02:23, Randy Brukardt wrote: > It's surely wrong, because you have to deallocate from the same pool as you > allocated. And you have no way to save such a thing. There is no capability > in Ada to use multiple pools with one access type. You mean Unchecked_Dellocation? Maybe, then it is another language bug. However, the object collection schema is irrelevant for a while. The first problem is that Finalize is called twice. > At best, you could directly call Allocate and Deallocate for this purpose, > but it is impossible to use anything built-in. Actually it is possible using a fake pool: type Fake_Pool is new Root_Storage_Pool with record Pool : access Root_Storage_Pool'Class; end record; Allocate goes like this: procedure Allocate ( Pool : in out Fake_Pool; Storage_Address : out System.Address; Size : Storage_Count; Alignment : Storage_Count ) is begin Pool.Pool.Allocate (Storage_Address, Size, Alignment); end Allocate; Then: Fake : Fake_Pool; type Ptr is access Item; for Ptr'Storage_Pool use Fake; -- "collection" lives here function New_Item ( Pool : in out Root_Storage_Pool'Class; Text : String ) return Item_Ptr is Object : Ptr; begin Fake.Pool := Pool'Unchecked_Access; -- Add mutex here Object := new Item (Text'Length); Object.Text := Text; return Object.all'Unchecked_Access; end New_Item; Now the object is intact. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-29 9:09 On absurdity of collections 7.6.1 (11.1/3) Dmitry A. Kazakov 2021-09-29 11:05 ` Simon Wright @ 2021-09-30 18:23 ` G.B. 2021-09-30 18:52 ` Dmitry A. Kazakov 1 sibling, 1 reply; 15+ messages in thread From: G.B. @ 2021-09-30 18:23 UTC (permalink / raw) On 29.09.21 11:09, Dmitry A. Kazakov wrote: > For Ada programmers who wonder what it is, What's the reasoning behind run-time selection of storage pools? ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-30 18:23 ` G.B. @ 2021-09-30 18:52 ` Dmitry A. Kazakov 2021-10-01 1:40 ` Randy Brukardt 0 siblings, 1 reply; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-09-30 18:52 UTC (permalink / raw) On 2021-09-30 20:23, G.B. wrote: > On 29.09.21 11:09, Dmitry A. Kazakov wrote: >> For Ada programmers who wonder what it is, > What's the reasoning behind run-time selection of storage pools? It happens quite frequently. Here is an example without controlled objects, just an illustration of a dynamically selected storage pool. Consider a JSON parser. It is be an Ada object with a buffer inside which size is a discriminant. On top of the buffer sits an arena pool. The parts of the parsed JSON object are allocated in the arena. After parsing the result can be used until the next parsing that will sweep the arena, no Unchecked_Deallocate. In this case the collection rule will have no effect since JSON objects do not require controlled components (or tasks, yet another thing killed by the collection). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-09-30 18:52 ` Dmitry A. Kazakov @ 2021-10-01 1:40 ` Randy Brukardt 2021-10-01 7:57 ` Dmitry A. Kazakov 0 siblings, 1 reply; 15+ messages in thread From: Randy Brukardt @ 2021-10-01 1:40 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:sj5127$1bbu$1@gioia.aioe.org... > On 2021-09-30 20:23, G.B. wrote: >> On 29.09.21 11:09, Dmitry A. Kazakov wrote: >>> For Ada programmers who wonder what it is, >> What's the reasoning behind run-time selection of storage pools? > > It happens quite frequently. Here is an example without controlled > objects, just an illustration of a dynamically selected storage pool. > > Consider a JSON parser. It is be an Ada object with a buffer inside which > size is a discriminant. On top of the buffer sits an arena pool. The parts > of the parsed JSON object are allocated in the arena. After parsing the > result can be used until the next parsing that will sweep the arena, no > Unchecked_Deallocate. > > In this case the collection rule will have no effect since JSON objects do > not require controlled components (or tasks, yet another thing killed by > the collection). To implement an arena pool, you need to use the subpool mechanism (which does properly handle finalization when you "sweep the pool" as you put it). Each "arena" is a separate subpool, and you can dump the entire subpool with Unchecked_Deallocate_Subpool. It helps to use the tool designed for the job. ;-) Randy. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: On absurdity of collections 7.6.1 (11.1/3) 2021-10-01 1:40 ` Randy Brukardt @ 2021-10-01 7:57 ` Dmitry A. Kazakov 0 siblings, 0 replies; 15+ messages in thread From: Dmitry A. Kazakov @ 2021-10-01 7:57 UTC (permalink / raw) On 2021-10-01 03:40, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:sj5127$1bbu$1@gioia.aioe.org... >> On 2021-09-30 20:23, G.B. wrote: >>> On 29.09.21 11:09, Dmitry A. Kazakov wrote: >>>> For Ada programmers who wonder what it is, >>> What's the reasoning behind run-time selection of storage pools? >> >> It happens quite frequently. Here is an example without controlled >> objects, just an illustration of a dynamically selected storage pool. >> >> Consider a JSON parser. It is be an Ada object with a buffer inside which >> size is a discriminant. On top of the buffer sits an arena pool. The parts >> of the parsed JSON object are allocated in the arena. After parsing the >> result can be used until the next parsing that will sweep the arena, no >> Unchecked_Deallocate. >> >> In this case the collection rule will have no effect since JSON objects do >> not require controlled components (or tasks, yet another thing killed by >> the collection). > > To implement an arena pool, you need to use the subpool mechanism (which > does properly handle finalization when you "sweep the pool" as you put it). > Each "arena" is a separate subpool, and you can dump the entire subpool with > Unchecked_Deallocate_Subpool. Not in this case, where all pool is arena. Allocate takes memory from the object's buffer. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2021-10-01 7:57 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-09-29 9:09 On absurdity of collections 7.6.1 (11.1/3) Dmitry A. Kazakov 2021-09-29 11:05 ` Simon Wright 2021-09-29 11:20 ` Dmitry A. Kazakov 2021-09-29 21:38 ` Simon Wright 2021-09-30 8:07 ` Dmitry A. Kazakov 2021-09-30 8:35 ` Simon Wright 2021-09-30 8:49 ` Dmitry A. Kazakov 2021-10-01 1:37 ` Randy Brukardt 2021-10-01 7:57 ` Dmitry A. Kazakov 2021-09-30 0:23 ` Randy Brukardt 2021-09-30 8:06 ` Dmitry A. Kazakov 2021-09-30 18:23 ` G.B. 2021-09-30 18:52 ` Dmitry A. Kazakov 2021-10-01 1:40 ` Randy Brukardt 2021-10-01 7:57 ` 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