|
Prev: About String
Next: Generic warning
From: Reinert Korsnes on 17 Jun 2008 04:07 I try to use a stack in my Ada program. Assume the package definition given below, and the follow code in my program: type Message_t; type Message_ta is access Message_t; package Message_Stack_p is new Stacks(Message_ta); Send_Stack : Message_Stack_p.Stack; Question: How can I be sure that "Send_Stack" is empty at the start of the program execution ? How can I make explicite that "Send_Stack" is empty in this case ? reinert ------------------------------------------------------------------ generic type Item is private; package Stacks is type Stack is private; procedure Push(S: in out Stack; X: in Item); procedure Pop(S: in out Stack; X: out Item); function N_elements(S : Stack) return Integer; private type Cell; type Stack is access Cell; type Cell is record Next : Stack; N : Integer; Value: Item; end record; end Stacks; --- package body Stacks is procedure Push(S: in out Stack; X: in Item) is begin if S /= null then S := new Cell'(S,S.N+1,X); else S := new Cell'(S,1,X); end if; end; procedure Pop(S: in out Stack; X: out Item) is begin X := S.Value; S := S.Next; end; function N_elements(S: Stack) return Integer is begin if S /= null then return S.N; else return 0; end if; end; end Stacks;
From: Dmitry A. Kazakov on 17 Jun 2008 04:50 On Tue, 17 Jun 2008 10:07:43 +0200, Reinert Korsnes wrote: > Assume the package definition given below, > and the follow code in my program: > > type Message_t; > type Message_ta is access Message_t; > package Message_Stack_p is new Stacks(Message_ta); > Send_Stack : Message_Stack_p.Stack; > > Question: How can I be sure that "Send_Stack" is empty > at the start of the program execution ? Hmm, "sure" in which sense? To make it visible for the reader? To specify in the contract of Stack that it is initially empty? As for implementation you posted, the stack is empty, because instances of access types are initialized with null (when not explicitly initialized otherwise). Below you declare: > type Stack is access Cell; And Send_Stack : Message_Stack_p.Stack; -- This will be null = empty Now side comments: 1. > procedure Pop(S: in out Stack; X: out Item) is > begin > X := S.Value; > S := S.Next; > end; This is a memory leak. If you allocated a stack element on push, you should free it on pop. 2. Package initialization is achieved as follows: package body P is ... begin ... -- Initialize package stuff end P; 3. Package initialization cannot help you here, because the package declares an abstract data type of which objects can be created long after the package itself was elaborated (initialized). 4. You have messages. Pointers to messages. These pointers are copied into dynamically allocated linked list called stack. How are you going to maintain this? Do you want to prevent messages from being copied? Then you should reconsider the design of messages allowing their queuing without stacks. Alternatively, do you want to copy messages upon queueing (to marshal them)? Then the queue should deal with unconstrained objects: generic type Message (<>) is private; package Queue is ... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Reinert Korsnes on 17 Jun 2008 05:14 Dmitry A. Kazakov wrote: > On Tue, 17 Jun 2008 10:07:43 +0200, Reinert Korsnes wrote: > >> Assume the package definition given below, >> and the follow code in my program: >> >> type Message_t; >> type Message_ta is access Message_t; >> package Message_Stack_p is new Stacks(Message_ta); >> Send_Stack : Message_Stack_p.Stack; >> >> Question: How can I be sure that "Send_Stack" is empty >> at the start of the program execution ? > > Hmm, "sure" in which sense? To make it visible for the reader? To specify > in the contract of Stack that it is initially empty? Yes, yes, to make it visible for the reader. > > As for implementation you posted, the stack is empty, because instances of > access types are initialized with null (when not explicitly initialized Yes, but I do not like things depend on the particular implementation :-) > otherwise). Below you declare: > >> type Stack is access Cell; > > And > > Send_Stack : Message_Stack_p.Stack; -- This will be null = empty > > > Now side comments: > > 1. > >> procedure Pop(S: in out Stack; X: out Item) is >> begin >> X := S.Value; >> S := S.Next; >> end; > > This is a memory leak. If you allocated a stack element on push, you > should free it on pop. How I free it? I may not have a deep enough understanding here :-) > > 2. Package initialization is achieved as follows: > > package body P is > ... > begin > ... -- Initialize package stuff > end P; > > 3. Package initialization cannot help you here, because the package > declares an abstract data type of which objects can be created long after > the package itself was elaborated (initialized). But I would like to make it clear for all that the stack is empty at the start of my program ! (also after that I may change the implementation). > > 4. You have messages. Pointers to messages. These pointers are copied into > dynamically allocated linked list called stack. > > How are you going to maintain this? Do you want to prevent messages from > being copied? Then you should reconsider the design of messages allowing > their queuing without stacks. Alternatively, do you want to copy messages > upon queueing (to marshal them)? Then the queue should deal with > unconstrained objects: > > generic > type Message (<>) is private; > package Queue is > ... > I want to "stack away" messages to be processed later. Copied, deleted etc. reinert
From: christoph.grein on 17 Jun 2008 06:18 On 17 Jun., 10:50, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de> wrote: > As for implementation you posted, the stack is empty, because instances of > access types are initialized with null (when not explicitly initialized > otherwise). Below you declare: > > > type Stack is access Cell; > > And > > Send_Stack : Message_Stack_p.Stack; -- This will be null = empty But N is undefined, so you have an empty stack with an undefined number of elements. There is no way to make it visible to users that the stack is empty after declaration of a stack object if you hide the implementation. You must state this as a comment; this belongs to the contract of the ADT and you must implement it fulfilling the contract: private type Cell; type Stack is access Cell; type Cell is record Next : Stack; N : Integer := 0; -- better use Natural here, or will you ever have a negative number of elements? Value: Item; end record; end Stacks; Your stack should be limited private - or do you want to copy stack objects? Then you must be careful that deep copies are made. With this design, you have no control over copying. A copy of a stack will be a shallow copy. For freeing cells, see Ada.Unchecked_Deallocation.
From: Dmitry A. Kazakov on 17 Jun 2008 06:26
On Tue, 17 Jun 2008 11:14:59 +0200, Reinert Korsnes wrote: > Dmitry A. Kazakov wrote: > >> On Tue, 17 Jun 2008 10:07:43 +0200, Reinert Korsnes wrote: >> >>> Question: How can I be sure that "Send_Stack" is empty >>> at the start of the program execution ? >> >> Hmm, "sure" in which sense? To make it visible for the reader? To specify >> in the contract of Stack that it is initially empty? > > Yes, yes, to make it visible for the reader. I.e. you want to allow initially non-empty stacks? This does not look like a good idea. Anyway, if stack is non-limited, you could do something like type Stack (<>) is private; -- The box <> enforces object's initialization Empty : constant Stack; -- Initial value of an empty stack ... private ... Empty : constant Stack := null; then the user will be forced to do: Send_Stack : Stack := Empty; However, I see no reason to have stack copyable in the first line. >> As for implementation you posted, the stack is empty, because instances of >> access types are initialized with null (when not explicitly initialized > > Yes, but I do not like things depend on the particular implementation :-) But this particular implementation fulfills the stack contract, which reads "stack is initially empty." I see no problem here. >>> procedure Pop(S: in out Stack; X: out Item) is >>> begin >>> X := S.Value; >>> S := S.Next; >>> end; >> >> This is a memory leak. If you allocated a stack element on push, you >> should free it on pop. > > How I free it? I may not have a deep enough understanding here :-) Per a call to instantiated Ada.Unchecked_Deallocation. procedure Pop (S: in out Stack; X: out Item) is procedure Free is new Ada.Unchecked_Deallocation (Cell, Stack); Top : Stack := S; begin if Top =null then raise Empty_Stack_Error; else X := Top.Value; S := Top.Next; Free (Top); end if; end Pop; BTW, you don't need to keep the stack depth in its items. Do it in the stack object. Increment it on push and decrement on pop. >> 3. Package initialization cannot help you here, because the package >> declares an abstract data type of which objects can be created long after >> the package itself was elaborated (initialized). > > But I would like to make it clear for all that the stack is > empty at the start of my program! But your program starts even before package elaboration. At that point there is no stack at all, whether empty or not... > (also after that I may > change the implementation). Any implementation shall respect the stack contract, and see above... >> How are you going to maintain this? Do you want to prevent messages from >> being copied? Then you should reconsider the design of messages allowing >> their queuing without stacks. Alternatively, do you want to copy messages >> upon queueing (to marshal them)? Then the queue should deal with >> unconstrained objects: >> >> generic >> type Message (<>) is private; >> package Queue is >> ... > > I want to "stack away" messages to be processed later. > Copied, deleted etc. That does not define what happens with the message object. Do you stack *the* message or *a* copy/equivalent/digest of? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |