Params by reference... is it possible?

Started by Joe, Sat 09/05/2009 13:28:50

Previous topic - Next topic

Joe

Does AGS let you do something like the known params by reference in C++?

in C++ you can do this:

Code: ags

void Read(int *p, int *c){
*p=GetSomethig();
*c=GetAnotherThing();
}

//And then you call the function like this:

Read(&myInt1, &myInt2);



This is very useful to make a function return more than one value so I'd like to do it in AGS, is it possible?

Thanks.
Copinstar © Oficial Site

monkey0506

#1
Unfortunately this isn't something supported by AGS at this time. There's not really even a comparable workaround. You could possibly define it as a member function of a struct and then reassign the struct members, but other than that you would have to manually assign the global variables.

Edit: Actually another possibility would be to use dynamic arrays. Then instead of global variables myInt1 and myInt2 you could have the array myInt:

Code: ags
int myInt[];

int[] Read() {
  int arr[] = new int[2];
  arr[0] = GetSomething();
  arr[1] = GetAnotherThing();
  return arr;
}

myInt = Read();

Joe

Hmmm interesting... never knew you could do that (int[]) with a function

Thanks monkey.
Copinstar © Oficial Site

monkey0506

Sure thing. Oh and just in case you did ever want to use a struct, you cannot have dynamic arrays as struct members or even import a function that returns a dynamic array into a struct. You can however have a struct extender method return a dynamic array, i.e.:

Code: ags
// script.ash
struct my_type {
  int my_int1;
  int my_int2;
  bool LoadFromArray(int arr[]);
};

import int[] GetArray(this my_type*);

// script.asc
bool LoadFromArray(int arr[]) {
  if (arr == null) return false;
  this.my_int1 = arr[0];
  this.my_int2 = arr[2];
  return true;
}

int[] GetArray(this my_type*) {
  int arr[] = new int[2];
  arr[0] = this.my_int1;
  arr[1] = this.my_int2;
  return arr;
}


With this you could even emulate a copy constructor as well:

Code: ags
my_type my_var1;
my_type my_var2;
int vals[] = new int[2];
vals[0] = 55;
vals[1] = 37;
my_var1.LoadFromArray(vals);
my_var2.LoadFromArray(my_var1.GetArray());


Not strictly the best example, but you get the idea, and it's some food for thought. ;)

Sephiroth

#4
Sorry if I'm wrong but I thought the variable scope would allow you to do something like this to simulate a "return several values":

Code: ags

struct Example {
String Name;
int coord_x;
int coord_y;
};

/* --------------- */

Example ex1;

function ReadStuff()
{
 //blabla
 ex1.Name    =  char.Name;
 ex1.coord_x =  char.X;
 ex1.coord_y =  char.Y;
}

ReadStuff();
Display( "My name's %s and I'm standing at X:%d / Y:%d .", ex1.Name,  ex1.coord_x,  ex1.coord_y );



You can modify a global var inside a local scope, so you can return as many values as you want if you simply fill up a struct that contains all the return values you need. Maybe you already know that and just wanted to check if a reference would work, anyways I hope it helps a bit.

Joe

Yeah that's right but it's not a global function, I mean, you cant use it with each "Exaple" you create but only with ex1.

BTW, You don't need to use String.Format in a Display function.
Copinstar © Oficial Site

Sephiroth

#6
What if you use ex1 as a global return value like I did and then use this whenever you create another 'example':

Code: ags

Example ex2;

ReadStuff();
ex2 = ex1;

Example ex3;

ReadStuff();
ex3 = ex1;


Would that work?

Edit: Yeah it was cEgo.Say when I wrote it, then I just changed to display, sorry. Btw I'd love to see an update so we could use this instead: Example ex1 = ReadStuff(); heh.

GarageGothic

This is really interesting, I had no idea you return an array. This will make a couple of my functions that return coordinate sets much easier to write, possibly also linebreaking code.

Sephiroth

Actually you 'return' a struct, so it could contain an array of int (e.g for tiles), a string, a bool and anything you define into one var. This is what I'm using for Tileset, Magics, Loots Tables structures in my code. But maybe monkey_05_06 's example is better, depends on the context and needs I think.

-Regards

monkey0506

#9
GG was actually referencing my code Sephiroth. ;) However, AGS currently doesn't support returning a struct from a function or the "ex2 = ex1" functionality you wrote earlier.

What you could do is use a struct member function like this:

Code: ags
struct Example {
  String Name;
  int coord_x;
  int coord_y;
  import void ReadStuff();
};

void Example::ReadStuff() {
  //blabla
  this.Name = char.Name;
  this.coord_x = char.X;
  this.coord_y = char.Y;
}

Example ex1;

ex1.ReadStuff();
Display("My name's %s and I'm standing at (X:%d, Y:%d).", ex1.Name,  ex1.coord_x,  ex1.coord_y);


Edit: Oh crap, I forgot to update to use the this pointer. Fixed that. Duh, that was the whole point of the member function.

P.S. GG, if you're interested my StringPlus module has several different String-splitting functions that all return a String[]. Feel free to take a look and copy/paste/edit/etc. whatever you like. Oh and on the note of dynamic arrays since there's currently no way of getting the size you'll need to track it separately. You can do this with a simple int variable, however I much prefer to pad the array by one index and store the size in arr[0].

Sephiroth

#10
Yeah right, member function will do, I don't know why we can't assign 2 struct variables of the same type  :-\
Same as passing a custom struct as a parameter I guess, sadly... 

But you could still do:

Code: ags

ex2.coord_x = ex1.coord_x;


Or directly use ex1 as in:
Code: ags

SetPosition();
Draw(ex1.Name, ex1.coord_x, ex1.coord_y);

Wait(100);

SetPosition();
Draw(ex1.Name, ex1.coord_x, ex1.coord_y);



Heh okay I thought he was talking about mine, sorry ;)

monkey0506

This type of thing has been requested several, several times before and it's always been marked as low-priority for various understandable reasons.

One of the most beneficial changes that could be made in this respect is if we could have pointers to custom structs which would open up whole new doors as far as the possibilities. However as CJ has said before there's one major road block here, specifically with regard to save games and the issue of custom pointer scope.

It's the reason AGS currently has managed types which CJ has specifically and explicitly dealt with. Implementing this would not be a simple change and would require a lot of work on CJ's part modifying several key parts of the compiler (which could inherently produce a lot of issues in itself) as well as the way that save game files are written (again holding the potential to open a huge can of worms).

Sure I'd love to see it happen, but it's no small venture and I think the recent developments Chris has been making very much outweigh the trouble he would have to go through, the time it would take for that feature to be released, the hours of debugging on everyone's part...we'll see it eventually, but for right now we just have to work around it. Honestly it's not that difficult, so it's not that big a deal IMO. ;)

Sephiroth

#12
QuoteOne of the most beneficial changes that could be made in this respect is if we could have pointers to custom structs which would open up whole new doors as far as the possibilities.

Operators support on custom types would help here, but I like how I can get the struct filled as a return value instead of having to deal with arrays and pointers this way I'm not restricted to one type as a return value and each of the function can 'return' a custom struct, in the example I did 'ex1' is a temp buffer to hold the return values, you can save the data it contains into other vars or use it in checks.

The problem is passing it directly as argument but it works as a retrun value holder to me.

-Regards

GarageGothic

Thanks monkey! I was aware of your module, but hadn't taken a closer look at it since I already had my own linebreak code. Now I'll definitely check out how you've set up the String array returns.

My problem was that I wanted to write a linebreaker that returned the first part of the broken String and updated the original String to only contain the remaining text, but as it turned out you can't change the String that the function was called on. This way I could simply return an String[2] array containing both Strings (I'm not interested in breaking the entire String at once because line length may change between lines, and the calling function needs to parse some html like tags that influence the rendering and text width).

Once again, thanks for pointing me in the right direction!

SMF spam blocked by CleanTalk