Weird pass by reference-ish problem

edited October 2013 in Questions about Code

I have a little code where a small pumpkin moves around the screen, with some obstacles and a potion it can drink to become bigger. However something happens that confuses me to the variable defaultSizePumpkin in the code below:

Pumpkin Jule;
String[] pumpkinPicNames;
boolean moveP=false, upP=false, downP=false, leftP=false, rightP=false; 
Obstacle[] obstacles;
Screen currentScreen;
int xstepFraction, ystepFraction;
float XSTEP, YSTEP;
Potion bigPotion;
float[] defaultSizePumpkin={8, 7};
boolean[] leavingScreen={false, false, false, false};

void keyPressed() {

  if(keyCode==UP) {
    upP=true;
    moveP=true;
  }
  if(keyCode==DOWN) {
    downP=true;
    moveP=true;
  }
  if(keyCode==LEFT) {
    leftP=true;
    moveP=true;
  }
  if(keyCode==RIGHT) {
    rightP=true;
    moveP=true;
  }
}


void setup() {

  size(displayWidth*4/5, displayHeight*4/5);
  xstepFraction=200; 
  ystepFraction=(int)(xstepFraction*height/width);
  XSTEP=width/(float)xstepFraction; 
  YSTEP=height/(float)ystepFraction;

  float[] obstacleColor={139, 117, 0};
  obstacles=new Obstacle[1];
  obstacles[0]=new Obstacle((int)(0.5*xstepFraction), (int)(0.5*ystepFraction), 
                   (int)(0.1*xstepFraction), (int)(0.1*ystepFraction), 
                   obstacleColor, "rectangle");
  bigPotion=new Potion("potionBig.jpg", (int)(0.85*xstepFraction), 
                   (int)(0.9*ystepFraction), 1.6);
  float[] startColor={0, 205, 205};
  currentScreen=new Screen(startColor);
  pumpkinPicNames=new String[1];
  pumpkinPicNames[0]="pumpkin.png";
  Jule=new Pumpkin(8, 7, defaultSizePumpkin, pumpkinPicNames, 4);

}

void draw() {

  currentScreen.drawScreen();
  currentScreen.drawObstacles();

  if(bigPotion.unDrunk){
    bigPotion.drawPotion(); 
    if(bigPotion.checkDrunk(Jule.x, Jule.y, Jule.size[0], Jule.size[1])) {
      if(Jule.changeSize(bigPotion.sizeModifier, true)) bigPotion.unDrunk=false;         
    }
  }

  Jule.drawPumpkin();

  if(moveP) {
    leavingScreen=Jule.move();
    moveP=false;
  }

}

class Screen {

  float[] colour;


  Screen(float colour[]) {

    this.colour=colour;

  }

  void drawScreen() {

    background(colour[0], colour[1], colour[2]);
  }

  void drawObstacles() {

    for(int i=0;i<obstacles.length;i++) obstacles[i].drawObstacle();
  }

}

class Pumpkin{
  int x, y, speed;
  PImage pumpkinPics[];
  float[] size;

  Pumpkin(int x, int y, float[] size, String[] pumpkinPicNames, int speed) {

    this.x=x;
    this.y=y;
    this.size=size;
    this.speed=speed;
    pumpkinPics = new PImage[pumpkinPicNames.length]; 
    for (int i = 0; i < pumpkinPicNames.length; i++) {
      pumpkinPics[i] = loadImage(pumpkinPicNames[i]);
    }


  }

  void drawPumpkin() {
    image(pumpkinPics[0], x*XSTEP, y*YSTEP, size[0]*XSTEP, size[1]*YSTEP);
  }

  boolean changeSize(float sizeModifier, boolean bigger) {
    boolean changed=false;
    if(bigger) { 
      if(size[0]<20) { 

       // At this point defaultSizePumpkin changes even though I'm altering size[]

        System.out.println("Before: "defaultSizePumpkin[0]+" "+defaultSizePumpkin[1]);
        size[0]*=sizeModifier; 
        size[1]*=sizeModifier;
        System.out.println("After: "+defaultSizePumpkin[0]+" "+defaultSizePumpkin[1]);

        changed=true; 
        speed=(int)(speed*sizeModifier);
        if(speed>6) speed=6;
      }
    }
    else {
      if(size[0]>3) {
        size[0]*=sizeModifier;
        size[1]*=sizeModifier;
        changed=true;
        speed=(int)(speed*sizeModifier);
        if(speed<1) speed=1;
      }
    }
    return changed;
  }

  int newStep (int stepx, int stepy)  {
    int tryStep=speed;
    for(int i=0;i<obstacles.length;i++) {
      while(x+stepx*tryStep+size[0]>obstacles[i].x && 
              x+stepx*tryStep<obstacles[i].x+obstacles[i].xlength &&
              y+stepy*tryStep+size[1]>obstacles[i].y && 
              y+stepy*tryStep<obstacles[i].y+obstacles[i].ylength) tryStep--;
    }
    return tryStep;
  }

  boolean[] move() {

    boolean leaving[]={false, false, false, false};

    if (upP) {
      y-=newStep(0, -1);
      upP=false;
    }
    else if (downP) {
      y+=newStep(0, 1);
      downP=false;
    }
    else if (leftP) {
      x-=newStep(-1, 0);
      leftP=false;
    }
    else if (rightP) {
      x+=newStep(1, 0);
      rightP=false;
    }

    if(x*XSTEP<0) leaving[0]=true;
    if((x+size[0])*XSTEP>width) leaving[1]=true;
    if(y*YSTEP<0) leaving[2]=true;
    if((y+size[1])*YSTEP>height) leaving[3]=true;

    return leaving;

  }

}

class Obstacle {
  float[] colour;
  int x, y, xlength, ylength;
  String type;

  Obstacle(int x, int y, int xlength, int ylength, float[] colour, String type) {
    this.x=x;
    this.y=y;
    this.xlength=xlength;
    this.ylength=ylength;
    this.colour=colour;
    this.type=type;

  }

  void drawObstacle() {
    if(type.equals("rectangle")) rectObstacle();
  }


  void rectObstacle() {
    strokeWeight(0);
    fill(colour[0], colour[1], colour[2]);
    rect(x*XSTEP, y*YSTEP, xlength*XSTEP, ylength*YSTEP, 7);
  }

}

class Potion{

  PImage potionPic;
  boolean unDrunk=true;
  int x, y;
  float[] size={4, 3};
  float sizeModifier;

  Potion(String potionPicName, int x, int y, float sizeModifier) {
    this.x=x;
    this.y=y;
    this.sizeModifier=sizeModifier;
    potionPic = loadImage(potionPicName);

  }

  void drawPotion() {
    image(potionPic, x*XSTEP, y*YSTEP, size[0]*XSTEP, size[1]*YSTEP);
  }

  boolean checkDrunk(int x, int y, float sizex, float sizey) {
    return((x+sizex/2>this.x && x+sizex/2<this.x+size[0] 
              && y+sizey/2>this.y && y+sizey/2<this.y+size[1]) || 
              (this.x>x && this.x+size[0]<x+sizex && 
               this.y>y && this.y+size[1]<y+sizey) );

  }

}

In the class Pumpkin, when changeSize is called, the value of defaultSizePumpkin changes, as seen from the output written to the console (see line 128). However this variable is given its value at the beginning of the program and then later only passed as a variable to constructors of classes. It seems almost to act like a call by reference in c++.

I haven't programmed so long in java and assume there's something I don't understand - can someone tell me why defaultSizePumpkin changes?

Answers

  • edited October 2013 Answer ✓

    In Java (C# and even D), any variable which isn't any of the 8 primitive data-types,
    stores a pointer reference value instead of a regular number value! :O

    For example, in something like -> float[] defaultSizePumpkin = {8, 7};
    that defaultSizePumpkin field is actually holding the physical memory address of a dynamically allocated Array object!

  • Thank you! I wasn't aware of that. That makes many things easier I realize, since that means e.g. user defined objects are passed by reference.

  • edited October 2013

    Technically speaking, even though a reference is passed as argument, it's still "passed by a copy of a value"! b-(
    That is, the value itself can be either a pointer reference or a regular value. But still it's the actual value stored in a variable!

    A true "passed by reference" as we see in languages like C is by an operator (&) which extracts a variable's memory address,
    or when a function can force a passed variable to yield its address!

    e.g. user defined objects are passed by reference.

    Actually, any non-primitive data-type is an object! No matter whether it's "user-defined" or not. L-)

Sign In or Register to comment.