From: Reinert Korsnes on
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
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
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
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
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
 |  Next  |  Last
Pages: 1 2 3
Prev: About String
Next: Generic warning