comp.lang.ada
 help / color / mirror / Atom feed
* Newbie's question
@ 2008-02-11 14:31 Christos Chryssochoidis
  2008-02-11 16:28 ` Newbie's question [SOLVED] Christos Chryssochoidis
  2008-02-11 17:42 ` Newbie's question Jeffrey R. Carter
  0 siblings, 2 replies; 5+ messages in thread
From: Christos Chryssochoidis @ 2008-02-11 14:31 UTC (permalink / raw)


Hello,

I 'm experimenting with Ada, and I'm having trouble getting some toy 
code running. The code is the following: (hope it isn't too complicated)


-- This is a program to test passing subprograms as arguments to other 
subprograms.
-- It consists of a main program, "Test_Filter", and two nested 
subprograms: "Filter" and "Greater_Equal_3". The "Filter" subprogram 
takes as arguments an array of Integers and a function (predicate), and 
returns an array of the same type, having only those elements of the 
input array that satisfy the given predicate. For some reason that I 
can't figure out, I'm getting a "segmentation fault" when I run the 
executable. (It compiles fine.)


with Ada.Containers.Doubly_Linked_Lists;
with Ada.Text_IO;

procedure Test_Filter is

    subtype Index is Natural;
    type Int_Array is array(Index range<>) of Integer;


    function Filter(Elements : Int_Array; Predicate : not null 
access 					function(Element : Integer) return Boolean) 								return 
Int_Array  is
       package Int_Lists is new 									 
Ada.Containers.Doubly_Linked_Lists(Element_Type => Integer);
       Tmp_List : Int_Lists.List;
       Result : access Int_Array;
    begin
       for I in Elements'Range loop
          if Predicate(Elements(I)) then
             Tmp_List.Append(Elements(I));
          end if;
       end loop;

       Result := new Int_Array(1..Index(Tmp_List.Length));
   Copy_List:
       declare
          Tmp_List_Cursor : Int_Lists.Cursor := Tmp_List.First;
          I : Integer := 1;
       begin
          while Int_Lists.Has_Element(Tmp_List_Cursor) loop
             Result(I) := Int_Lists.Element(Tmp_List_Cursor);
             Tmp_List_Cursor := Int_Lists.Next(Tmp_List_Cursor);
             I := I + 1;
          end loop;
       end Copy_List;

       return Result.all;

    end Filter;

    function Greater_Equal_3(Element :Integer) return Boolean is
    begin
       if Element >= 3 then
          return True;
       else
          return False;
       end if;
    end Greater_Equal_3;


    Int_Array1 : Int_Array := Int_Array'(1,2,3,4,5);
    Int_Array2 : Int_Array(1..3);

begin
    Int_Array2 := Filter(Int_Array1, Greater_Equal_3'Access);
    for I in Int_Array1'Range loop
       Ada.Text_IO.Put_Line(Int_Array1(I)'Img);
    end loop;

    Ada.Text_IO.Put_Line("");

    for I in Int_Array2'Range loop
       Ada.Text_IO.Put_Line(Int_Array2(I)'Img);
    end loop;

end Test_Filter;


Thanks very much for any help.



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

* Re: Newbie's question [SOLVED]
  2008-02-11 14:31 Newbie's question Christos Chryssochoidis
@ 2008-02-11 16:28 ` Christos Chryssochoidis
  2008-02-11 17:42 ` Newbie's question Jeffrey R. Carter
  1 sibling, 0 replies; 5+ messages in thread
From: Christos Chryssochoidis @ 2008-02-11 16:28 UTC (permalink / raw)



I changed version of GNAT and now the code runs ok.



Christos Chryssochoidis wrote:
> 
> Hello,
> 
> I 'm experimenting with Ada, and I'm having trouble getting some toy 
> code running. The code is the following: (hope it isn't too complicated)
> 
> 
> -- This is a program to test passing subprograms as arguments to other 
> subprograms.
> -- It consists of a main program, "Test_Filter", and two nested 
> subprograms: "Filter" and "Greater_Equal_3". The "Filter" subprogram 
> takes as arguments an array of Integers and a function (predicate), and 
> returns an array of the same type, having only those elements of the 
> input array that satisfy the given predicate. For some reason that I 
> can't figure out, I'm getting a "segmentation fault" when I run the 
> executable. (It compiles fine.)
> 
> 
> with Ada.Containers.Doubly_Linked_Lists;
> with Ada.Text_IO;
> 
> procedure Test_Filter is
> 
>    subtype Index is Natural;
>    type Int_Array is array(Index range<>) of Integer;
> 
> 
>    function Filter(Elements : Int_Array; Predicate : not null 
> access                     function(Element : Integer) return 
> Boolean)                                 return Int_Array  is
>       package Int_Lists is new                                      
> Ada.Containers.Doubly_Linked_Lists(Element_Type => Integer);
>       Tmp_List : Int_Lists.List;
>       Result : access Int_Array;
>    begin
>       for I in Elements'Range loop
>          if Predicate(Elements(I)) then
>             Tmp_List.Append(Elements(I));
>          end if;
>       end loop;
> 
>       Result := new Int_Array(1..Index(Tmp_List.Length));
>   Copy_List:
>       declare
>          Tmp_List_Cursor : Int_Lists.Cursor := Tmp_List.First;
>          I : Integer := 1;
>       begin
>          while Int_Lists.Has_Element(Tmp_List_Cursor) loop
>             Result(I) := Int_Lists.Element(Tmp_List_Cursor);
>             Tmp_List_Cursor := Int_Lists.Next(Tmp_List_Cursor);
>             I := I + 1;
>          end loop;
>       end Copy_List;
> 
>       return Result.all;
> 
>    end Filter;
> 
>    function Greater_Equal_3(Element :Integer) return Boolean is
>    begin
>       if Element >= 3 then
>          return True;
>       else
>          return False;
>       end if;
>    end Greater_Equal_3;
> 
> 
>    Int_Array1 : Int_Array := Int_Array'(1,2,3,4,5);
>    Int_Array2 : Int_Array(1..3);
> 
> begin
>    Int_Array2 := Filter(Int_Array1, Greater_Equal_3'Access);
>    for I in Int_Array1'Range loop
>       Ada.Text_IO.Put_Line(Int_Array1(I)'Img);
>    end loop;
> 
>    Ada.Text_IO.Put_Line("");
> 
>    for I in Int_Array2'Range loop
>       Ada.Text_IO.Put_Line(Int_Array2(I)'Img);
>    end loop;
> 
> end Test_Filter;
> 
> 
> Thanks very much for any help.



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

* Re: Newbie's question
  2008-02-11 14:31 Newbie's question Christos Chryssochoidis
  2008-02-11 16:28 ` Newbie's question [SOLVED] Christos Chryssochoidis
@ 2008-02-11 17:42 ` Jeffrey R. Carter
  2008-02-12 22:56   ` Christos Chryssochoidis
  1 sibling, 1 reply; 5+ messages in thread
From: Jeffrey R. Carter @ 2008-02-11 17:42 UTC (permalink / raw)


Christos Chryssochoidis wrote:

Apparently you found a compiler error. Some comments on your code:

>       Result : access Int_Array;
>    begin
>       for I in Elements'Range loop
>          if Predicate(Elements(I)) then
>             Tmp_List.Append(Elements(I));
>          end if;
>       end loop;
> 
>       Result := new Int_Array(1..Index(Tmp_List.Length));

This is OK for a little test program like this, but in real code, you have a 
memory leak from this use of access values and heap allocation that you should 
want to avoid. You can do that by moving the declaration of Result into 
Copy_List below:

Result : Int_Array (1 .. Index (Tmp_List.Length) );

You might also find an unbounded array (Ada.Containers.Vectors) more suited than 
a list here, since you can use the same index for both.

>   Copy_List:
>       declare
>          Tmp_List_Cursor : Int_Lists.Cursor := Tmp_List.First;
>          I : Integer := 1;
>       begin
>          while Int_Lists.Has_Element(Tmp_List_Cursor) loop
>             Result(I) := Int_Lists.Element(Tmp_List_Cursor);
>             Tmp_List_Cursor := Int_Lists.Next(Tmp_List_Cursor);
>             I := I + 1;
>          end loop;
>       end Copy_List;

Rather than using a cursor and a loop, I would probably use the Iterate 
procedure to convert the list into an array.

You could also make Filter recursive and eliminate Result and Tmp_List altogether:

begin -- Filter
    if Elements'Length <= 0 then
       return Elements;
    elsif Predicate (Elements (Elements'First) ) then
       return Elements'First &
              Filter (Elements (Elements'First + 1 .. Elements'Last), Predicate);
    else
       return Filter (Elements (Elements'First + 1 .. Elements'Last), Predicate);
    end if;
end Filter;

>    function Greater_Equal_3(Element :Integer) return Boolean is
>    begin
>       if Element >= 3 then
>          return True;
>       else
>          return False;
>       end if;
>    end Greater_Equal_3;

This should be

return Element >= 3;

Personally, I'd make filter generic rather than passing the Predicate function 
as a subprogram parameter.

-- 
Jeff Carter
"Spam! Spam! Spam! Spam! Spam! Spam! Spam! Spam!"
Monty Python's Flying Circus
53



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

* Re: Newbie's question
  2008-02-11 17:42 ` Newbie's question Jeffrey R. Carter
@ 2008-02-12 22:56   ` Christos Chryssochoidis
  2008-02-13 11:06     ` Christos Chryssochoidis
  0 siblings, 1 reply; 5+ messages in thread
From: Christos Chryssochoidis @ 2008-02-12 22:56 UTC (permalink / raw)




Jeffrey R. Carter wrote:
> 
> Christos Chryssochoidis wrote:
> 
> Apparently you found a compiler error. Some comments on your code:
> 
>>       Result : access Int_Array;
>>    begin
>>       for I in Elements'Range loop
>>          if Predicate(Elements(I)) then
>>             Tmp_List.Append(Elements(I));
>>          end if;
>>       end loop;
>>
>>       Result := new Int_Array(1..Index(Tmp_List.Length));
> 
> This is OK for a little test program like this, but in real code, you 
> have a memory leak from this use of access values and heap allocation 
> that you should want to avoid. You can do that by moving the declaration 
> of Result into Copy_List below:
> 
> Result : Int_Array (1 .. Index (Tmp_List.Length) );

I ruled out the declaration of a local array within the block statement 
Copy_List, because I thought that the compiler would mandate a return 
statement to be at the top level of the function's body, which I 
wouldn't be able to do, since the declared array would be local to the 
block statement. Surprisingly I realized I was wrong; this solution 
compiles fine. The compiler doesn't complain about not finding a return 
statement at the outermost scope of the function.



> 
> You might also find an unbounded array (Ada.Containers.Vectors) more 
> suited than a list here, since you can use the same index for both.

Good point.

> 
>>   Copy_List:
>>       declare
>>          Tmp_List_Cursor : Int_Lists.Cursor := Tmp_List.First;
>>          I : Integer := 1;
>>       begin
>>          while Int_Lists.Has_Element(Tmp_List_Cursor) loop
>>             Result(I) := Int_Lists.Element(Tmp_List_Cursor);
>>             Tmp_List_Cursor := Int_Lists.Next(Tmp_List_Cursor);
>>             I := I + 1;
>>          end loop;
>>       end Copy_List;
> 
> Rather than using a cursor and a loop, I would probably use the Iterate 
> procedure to convert the list into an array.

I tried it. (Code below.) It works fine. Thanks.


Copy_List:
       declare
          Result : Int_Array(0..Index(Tmp_Vector.Length)-1);
          I : Integer := 0;
          procedure Copy(Position: Int_Vectors.Cursor) is
          begin
             Result(I) := Int_Vectors.Element(Position);
             I := I + 1;
          end Copy;

       begin
          Tmp_Vector.Iterate(Copy'Access);

          return Result;
       end Copy_List;





> 
> You could also make Filter recursive and eliminate Result and Tmp_List 
> altogether:
> 
> begin -- Filter
>    if Elements'Length <= 0 then
>       return Elements;
>    elsif Predicate (Elements (Elements'First) ) then
>       return Elements'First &
>              Filter (Elements (Elements'First + 1 .. Elements'Last), 
> Predicate);
>    else
>       return Filter (Elements (Elements'First + 1 .. Elements'Last), 
> Predicate);
>    end if;
> end Filter;

I thought too about doing it recursively, but stubbornly I wanted to 
find a way to do that iteratively, as that's how I would do it in other 
languages I 'm familiar with…

> 
>>    function Greater_Equal_3(Element :Integer) return Boolean is
>>    begin
>>       if Element >= 3 then
>>          return True;
>>       else
>>          return False;
>>       end if;
>>    end Greater_Equal_3;
> 
> This should be
> 
> return Element >= 3;

That's much simpler, I agree.

> 
> Personally, I'd make filter generic rather than passing the Predicate 
> function as a subprogram parameter.
> 

I made another version of my code using a generic subprogram as you 
suggested. That's also an elegant solution.

Thanks very much for all your suggestions.



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

* Re: Newbie's question
  2008-02-12 22:56   ` Christos Chryssochoidis
@ 2008-02-13 11:06     ` Christos Chryssochoidis
  0 siblings, 0 replies; 5+ messages in thread
From: Christos Chryssochoidis @ 2008-02-13 11:06 UTC (permalink / raw)



 From a reply I received in private, it seems that the "generic" version 
of that code of mine is of interest for some, so I post it, making no 
claim that it is well written…







with Ada.Containers.Vectors;
with Ada.Text_IO;

procedure Test_Filter is

    subtype Index is Natural;
    type Int_Array is array(Index range<>) of Integer;


    generic
       with function Predicate(Element : Integer) return Boolean;
    function Filter(Elements : Int_Array) return Int_Array;


    function Filter(Elements : Int_Array) return Int_Array is
       package Int_Vectors is new Ada.Containers.Vectors(Element_Type => 
Integer, Index_Type => Index);
       Tmp_Vector : Int_Vectors.Vector;


    begin
       for I in Elements'Range loop
          if Predicate(Elements(I)) then
             Tmp_Vector.Append(Elements(I));
          end if;
       end loop;

   Copy_Vector:
       declare
          Result : Int_Array(0..Index(Tmp_Vector.Length)-1);
          I : Integer := 0;
          procedure Copy(Position: Int_Vectors.Cursor) is
          begin
             Result(I) := Int_Vectors.Element(Position);
             I := I + 1;
          end Copy;

       begin
          Tmp_Vector.Iterate(Copy'Access);

          return Result;
       end Copy_Vector;



    end Filter;

    function Greater_Equal_3(Element :Integer) return Boolean is
    begin
       return Element <= 3;
    end Greater_Equal_3;


    Int_Array1 : Int_Array := (1,2,3,4,5);
    Int_Array2 : Int_Array(1..3);
    function My_Filter is new Filter(Predicate=>Greater_Equal_3);
begin
    Int_Array2 := My_Filter(Int_Array1);
    for I in Int_Array1'Range loop
       Ada.Text_IO.Put_Line(Int_Array1(I)'Img);
    end loop;

    Ada.Text_IO.Put_Line("");

    for I in Int_Array2'Range loop
       Ada.Text_IO.Put_Line(Int_Array2(I)'Img);
    end loop;

end Test_Filter;



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

end of thread, other threads:[~2008-02-13 11:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-11 14:31 Newbie's question Christos Chryssochoidis
2008-02-11 16:28 ` Newbie's question [SOLVED] Christos Chryssochoidis
2008-02-11 17:42 ` Newbie's question Jeffrey R. Carter
2008-02-12 22:56   ` Christos Chryssochoidis
2008-02-13 11:06     ` Christos Chryssochoidis

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