1

I have a variable in a package (rec in this case) that needs to be set when called from package 3, but it's private. Previously the function set_true only set rec to true, so it wasn't a big deal. But I have another package that does the same processing (I'm giving a simple example, but my literal case is more complex), so I thought, well I could pass in the variable I want modified, and let it get changed. Is the only way to set rec in the below layout, to create a second function in package one, that calls set_true with rec as the parameter? I would like to avoid having to keep creating additional functions to handle the local variables. I can't move the variable to public (spec) as I am trying to follow convention and this "type" of variable isn't public anywhere else, and I don't want anyone to be able to just set it on their own (I want functions to have to set). I don't want to have to create a second function named for example set_local_true, and creating an overloaded function set_true, with no parameters, that calls set_true(value => rec) just seems deceptive, does anyone have any better suggestions with the limitations I have?

My two requirements:

  1. Can't make the local variable public.
  2. Be able to use the function to calculate something both externally and internally.
package one is
   procedure set_true(value : out Boolean);
end one;

package body one is
   rec : Boolean;
begin
   procedure set_true(value : out Boolean)
   begin
      value := true;
   end set_true;
end one;

package body two is
   local_rec : Boolean;
begin
   procedure call_function is
   begin
      one.set_true(value => local_rec);
   end call_function;
end two;

package body three is
begin
   procedure call_function is
   begin
      one.set_true(value => <PACKAGE ONE'S REC))
   end call_function;
end three;

EDIT: Or perhaps, what would be a better naming convention for the functions to specify that they are modifying the variable that is local to that package? Set_Local_True again is deceptive cause if you call it from package 3, you're not setting your local true, you're setting package one's local to true....

Chris
  • 26,361
  • 5
  • 21
  • 42
onaclov2000
  • 5,741
  • 9
  • 40
  • 54

2 Answers2

1

First off, this is very silly code. I'll assume it is shorthand for something else. But as presented, I can assure you that your clients can set their own booleans themselves without you writing a routine to do it for them. In fact, they can do it better. For the remainder of this answer, I'll assume you aren't acutally writing variables to set booleans for people, but rather doing something of actual use. If not, ignore the rest of this answer and just delete your silly routines.

Secondly, if you are creating a routine with a single out parameter, then unless the object happens to be very large, you should probably make it a function instead. That will allow your clients to use functional programming if they chose. The way you have it, the poor coder has to stop and create a special variable just to call your routine, even if they only want to do it once.

Thirdly, rather than using a unique set routine for each state, I generally prefer to pass in the requested state.

function Set_Frobnost (New_State : boolean := true) return boolean;

If the state is really and truly boolean (no possible third state in the future), then it is debateable. However, it can be a big advantage to your client if they might already have to store the state in a variable (or loop through it).

Your edit about naming shows me you are on the right track.

You should do one of two things here.

  1. Find the higher-level concept controlled by that variable, and name the "setter" routine after that.
  2. Get the hell out of the way and put the flag variable in the pacakge spec.
T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • I was trying to give a simple example, I can't post the literal code, but I was posting a similar version, I am actually passing in about 8 variables in one case (I know I know, 8 variables....), but it's required for the situation. Essentially a case statement happens and two of the variables get set to a specific value, and the others don't get touched. I like your suggestions though! – onaclov2000 Jan 11 '11 at 16:20
  • Well, if most of those parameters have logical defaults, put them at the end of the parameter list with default values. If not, then make your own class (package w/ abstract data type) out of them. That many parameters indicates that meerly setting up a call to your routine is a chore itself. Software should do our chores for us. :-) – T.E.D. Jan 11 '11 at 16:26
  • @T.E.D Unfortunately when I tried compiling "out" parameters can't be defaulted, and all of them are out parameters, Could you give a short example of what you mean by a package with abstract data type? I mean I considered putting them into an array and just passing an array, is there a lot of difference in that idea and yours? Also the "defaults" typically are handled in the calling package and are already defaulted before passed to the procedure. – onaclov2000 Jan 11 '11 at 16:47
  • No, you can't default out parameters. The trick I use there is overloading. Make routines with an identical interface, but without the parameters you don't care about. – T.E.D. Jan 11 '11 at 17:14
  • ...as for ADT's, check out whatever Ada book you use for learning. The basic idea is to put all your "parameters" in one record, and put that in a package with some routines for dealing with it (probably including these "set" routines of yours). The record can be `tagged` if you want to use inheritence, but that isn't nessecary. That way calling your routine can be a matter of one or two lines of code, rather than the 17 or so you tend to see if everything has to be separately declared and initialized. – T.E.D. Jan 11 '11 at 17:19
  • Unfortunately my "ada book" is google and the code base I'm updating. I think I understand what you're saying now about the ADT's. I also did end up using Overloading, I was originally under the impression I couldn't use overloading, now that I can it makes more sense. – onaclov2000 Jan 13 '11 at 15:23
1

If you have to access private variables, you might to do it in a child package.

package One is
   procedure Foo (X : Boolean);
private
   One_Private : Boolean;
end One;

and then

package body One.Two is
    procedure Bar is
       One.Foo (One.One_Private);
    end Bar;
end One.Two;

Elements in the "private" part of a package are like "protected" entities in C++/Java. Truly private variables (only in package body) are not accessible from anywhere else.

Rommudoh
  • 1,844
  • 10
  • 11