Returning PVector from a function

Hi guys,
What is the best practice for functions that need to return a PVector, given that it’s a reference type?
Consider the below code

void SomeBigCalculation ()
{
// Just temporarily need to know the relative position of the ship
PVector relativePos = CalculateRelativePos(ship.position);
\\ do something with relativePos...
}
PVector CalculateRelativePos(PVector location)
{
return new PVector(location.x + 1.0, location.y + 1.0);
}

So in this case, we’re minting a new PVector with every call to CalculateRelativePos(). That’s not so bad here, but it feels very inefficient to do this many times in a frame.
So in my program I have created vectors that exist purely as a “cache” for vector calculations, like this:

PVector _vecCache = new PVector();
void SomeBigCalculation ()
{
CalculateRelativePos(ship.position, _vecCache);
\\ do something with _vecCache...
}
void CalculateRelativePos(PVector location, PVector result)
{
result.x = location.x + 1.0;
result.y = location.y + 1.0;
}
…but this is obviously very ugly, as for one thing, we’ve lost the clear naming in the calling function. For another, I can no longer chain these function calls together.

1 Like

Hope I understand you correctly. To return a PVector the function cannot be void but must be defined as a PVector type. Like this:

PVector SomeBigCalculation(PVector locationA, PVector locationB){

PVector resultOfCalculation = new PVector();


your calculation

return resultOfCalculation;
}

If you call the function you need a PVector to get the result stored.

PVector test = SomeBigCalculation(locationA,locationB)
4 Likes

that’s what you want to avoid. (I think Divitiacus overlooked this.)

to make it less inefficient (as you wrote), we don’t want to use new throughout but only set() command.

I don’t know if this is really more efficient though.

Here is my idea:

  • Making relativePos global, only one new command needed. Good.
  • Use set() to assign it a new value. Hopefully faster than new.
  • Disadvantage: an additional global var. Not so nice.
  • Nice way of calling CalculateRelativePos() without any other PVector involved imho.
PVector relativePos = new PVector(0, 0); 


void SomeBigCalculation () {
  // Just temporarily need to know the relative position of the ship
  relativePos.set ( CalculateRelativePos(ship.position) );

  \\ do something with relativePos...
}

PVector CalculateRelativePos(PVector location) {
  return new PVector(location.x + 1.0, location.y + 1.0);
}

2 Likes

Hello @Mijin ,

I often glean insight from the source code.

Many of the PVector class methods return a PVector:
https://processing.github.io/processing-javadocs/core/index.html?processing/core/PVector.html

One example (give it a moment to go to the line):
https://github.com/processing/processing4/blob/main/core/src/processing/core/PVector.java#L731

:)

2 Likes

to make it less inefficient (as you wrote), we don’t want to use new throughout but only set() command.

I don’t know if this is really more efficient though.

I would be interested to know, if there is an efficiency loss, when “creating” all the variables new with each call of the function.

I do that intentionally that I “create” all variables new, which I need in a function, with each call. This way I can be sure, that there are no headaches with carry over values from previous uses of the function.

I would find it very inefficient from a programming perspective to make all variables globals and then to police them through the whole program code.

But I would like to know, if that really slows anything down.

2 Likes

I suggest using something like this

PVector CalculateRelativePos(PVector location, PVector target) {
  if (target == null) target = new PVector();
  target.set(location.x + 1.0, location.y + 1.0);
  return target;
}

This gives you the benefit of using either approach. If you pass null as the second parameter like this
CalculateRelativePos(loc, null)

then a new object is created or you could pass a cached vector (temp) like this.
CalculateRelativePos(loc, temp)

4 Likes

We can clean call it w/o null by creating an overloaded signature for CalculateRelativePos():

PVector CalculateRelativePos(PVector location) {
  return CalculateRelativePos(location, null);
}
3 Likes

Great thanks for the responses, and sorry for the poor code formatting on my part.
I will try the “use target if non-null, otherwise return new” approach :slight_smile:

1 Like

This is only necessary when you don’t know the usage of the function (to keep the function working in different Sketches).

Once you know the Sketch you can get rid of the if