comp.lang.ada
 help / color / mirror / Atom feed
From: Jeffrey Carter <spam@spam.com>
Subject: Re: Modes (was unbounded_string)
Date: Fri, 10 Oct 2003 19:06:00 GMT
Date: 2003-10-10T19:06:00+00:00	[thread overview]
Message-ID: <sqDhb.6123$dn6.5019@newsread4.news.pas.earthlink.net> (raw)
In-Reply-To: <mailman.60.1065773352.25614.comp.lang.ada@ada-france.org>

Andrew Carroll wrote:

>>>For all other types, the compiler chooses the parameter 
>>>mode best suited to the type. 

If I wrote that, then I made an error. It should be, "the compiler
chooses the parameter passing mechanism best suited to the type."

> package x is
> type x;
> type xptr is access x;
> type x is tagged limited record
>  head: nodeptr; 
>  something: unbounded_string;
> end record;
> 
> --creates a new node to put into the 'head' list.
> --new node is created from information in token.
> --token has nothing to do with the 'something' variable
> --declared in the record above.
> procedure add(this: xptr; token: unbounded_string); 
> 
> end x;
> 
> So, with the above code "example", xptr is passed as an 'in'
> or 'in out' mode at the add procedure?  

Since you didn't specify the mode, the mode is "in". That has nothing to
do with the parameter passing mechanism.

> Are you saying that I should use just x and not xptr as the
> parameter so that the compiler will choose the correct mode?

Since you seem to be dealing with a dynamically allocated structure,
then pointers are probably fine for implementing the structure. But 
there seems to no need for the client to pass in a value of type X or 
Xptr. There is even no need for the client to know about the details of 
these types. Instead, you should have a Head_List type which is 
[limited] private; the client should pass in an object of type Head_List 
(mode in out, so it can be modified), and a value of type 
Unbounded_String to add to the Head_List. Add allocates a new node and 
links it into the list. Head_List should probably be controlled so you 
can manage its memory.

> If so, you recommend it because of deallocation issues?

Precisely. With the pointer type exposed, and the client required to use 
it, the client becomes responsible for memory management and it has to 
be scattered all over the client's code. It's practically impossible to 
avoid errors that way. With the implementation hidden, all the memory 
management is in one place. Getting it right is easier; finding and 
fixing errors is easier. The client's code is simpler.

> Is there something in the code below that I missed about information 
> hiding?  
> 
> Temp: gnat.os_lib.String_Access;
> ...
> Temp := gnat.os_lib.getenv("QUERY_STRING");
> ...
> ---------------------------------------
> -- ready to use Temp for something else
> ---------------------------------------
> Temp := gnat.os_lib.getenv("SOME_OTHER_VARIABLE");

Since GNAT.OS_Lib.Getenv returns type String_Access, you have to use 
String_Access if you want to use Getenv. But note the description of 
Getenv from GNAT.OS_Lib:

--  Get the value of the environment variable. Returns an access
--  to the empty string if the environment variable does not exist
--  or has an explicit null value (in some operating systems these
--  are distinct cases, in others they are not; this interface
--  abstracts away that difference. The argument is allocated on
--  the heap (even in the null case), and needs to be freed explicitly
--  when no longer needed to avoid memory leaks.

Your code leaks memory, because the package has dumped the memory 
management onto the client, and you haven't done it. This is not, in my 
opinion, a good way to do this. Getenv should return a string, and deal 
with any memory management issues.

Note that Kazakov's versions using Unbounded_String and renaming the 
string pointed to also leak memory.

> Considering the code above, what is the "Ada idiom" to "resize" a String
> without pointers and dynamic allocation?  In other words; what "Ada 
> idiom" code would you write to do the same thing I did, without pointers
> and dynamic allocation?  You don't have to write the code, a good 
> reading reference would be okay.

If you have to use GNAT.OS_Lib.Getenv, I would do something like

declare
    Temp : String_Access := Getenv;

    Env : constant String := Temp.all;
begin
    Free (Temp);
    -- Deal with Env
end;

If you're speaking in general about having a string object that can hold 
values of different lengths, then you want to use Ada.Strings.[Un]Bounded.

Something : Unbounded_String;

function Get return String is ...;
...
Something := To_Unbounded_String (Get);
...
-- Repeat as desired

Very often in Ada, though, you can create [constant] Strings as you go, 
eliminating the need for [Un]Bounded_String.

-- 
Jeff Carter
"C++ is like jamming a helicopter inside a Miata
and expecting some sort of improvement."
Drew Olbrich
51




  parent reply	other threads:[~2003-10-10 19:06 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20031010074015.761204C40C1@lovelace.ada-france.org>
2003-10-10  8:27 ` Modes (was unbounded_string) Andrew Carroll
2003-10-10  9:15   ` Dmitry A. Kazakov
2003-10-11  7:16     ` Simon Wright
2003-10-13  9:28       ` Dmitry A. Kazakov
2003-10-10 15:18   ` Stephen Leake
2003-10-10 16:21     ` Martin Dowie
2003-10-14 18:47     ` Craig Carey
2003-10-10 19:06   ` Jeffrey Carter [this message]
2003-10-13  9:33     ` Dmitry A. Kazakov
2003-10-13  9:40       ` Stephane Richard
2003-10-13 10:12         ` Dmitry A. Kazakov
2003-10-15  2:16         ` Warren W. Gay VE3WWG
2003-10-15  3:36           ` Jeff C,
2003-10-16 16:45             ` Warren W. Gay VE3WWG
     [not found] <20031010094017.680474C40C1@lovelace.ada-france.org>
2003-10-10 10:58 ` Andrew Carroll
replies disabled

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