Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Function pointers

Name: Brunch 2012-08-09 9:20

Heya /prog/. I'm programming in java and there's something that really bothers me about my code. I'll write pseudocode so it's easier to see what I mean so don't get picky on syntax.


class entity {
   int action = IDLE;

   void idle() { void; };
   void moveRight() { ... };
   void jump() { ... };

   void onUpdate() {
      switch(action) {
           case IDLE: idle(); break;
           case JUMPING: jump(); break;
           case MOVINGRIGHT: moveRight(); break;
          
           ...
      }
  }
}


Now this really bothers me because you have this pile of ifs depending on status. It would, in my opinion, look much better if action was a pointer to a function.

class entity {
   function_pointer action = idle;

   void idle() { void; };
   void moveRight() { ... };
   void jump() { ... };

   void onUpdate() {
       function_pointer();
  }

But apparently java doesn't have this functionality. Or does it?
What do you think? Have any solutions to this?

Name: Anonymous 2012-08-09 9:36

It's possible, but you're going to have to do a lot of exception handling (or rethrow them packed in RuntimeException) and if you refactor your methods, then the refactoring tool won't pick up this stuff without some additional work. Take a look at java.lang.reflection.

I don't know the parameter list by heart, but something similar should do:

class Entity{

Method reflectiveMethod;

static {
m = Entity.class.getMethod("idle");
}

void setAction(String mName) {
m = getClass().getMethod(mName);
}

void onUpdate() {
m.invoke(this);
}

}

Generally, java.lang.reflection can do anything that a more dynamic language could do, but it can be quite a hassle to handle it. Also, in this particular case, you're probably better off just using an internal state instance and dynamic binding or (since your code looks like it is going to be used for a game) do it the way you do, because it's pretty fast and does not waste memory or CPU time on state change.

Name: Anonymous 2012-08-09 9:41

>>2

Also, I don't know how far the code you posted here strays from the actual code for sake of simplicity, but it seems like you could entirely avoid the problem by not using a software design that totally sucks.

Name: Anonymous 2012-08-09 9:44

>>2

static {
 m = Entity.class.getMethod("idle");
 }

should be

Entity() {
reflectiveMethod = getClass().getMethod("idle");
}

Name: Anonymous 2012-08-09 10:22

Yes welcome to the world of static OOP.
Where a first class function problem turns into pattern problem.
http://en.wikipedia.org/wiki/Command_pattern

Name: Anonymous 2012-08-09 10:37


interface IAction {
  void execute();
}

interface IEntity {
  void idle();
  void jump();
  void moveRight();
}

class ActionIdle implements IAction {
  private IEntity subject;

  ActionIdle(IEntity subject) {
    this.subject = subject;
  }

  public void execute() {
    subject.idle();
  }
}

class ActionJump implements IAction {
  private IEntity subject;

  ActionJump(IEntity subject) {
    this.subject = subject;
  }

  public void execute() {
    subject.jump();
  }
}

class ActionMoveRight implements IAction {
  private IEntity subject;

  ActionMoveRight(IEntity subject) {
    this.subject = subject;
  }

  public void execute() {
    subject.moveRight();
  }
}


abstract class SimpleEntity implements IEntity {
  IAction currentAction;

  SimpleEntity(IAction currentAction) {
    this.currentAction = currentAction;
  }

  public void onUpdate() {
    currentAction.execute();
  }
}

Name: Anonymous 2012-08-09 11:13

I don't know Java well, but can't you do something like the following (in CLOS)?
(defclass action () ())
(defclass idle (action) ())
(defclass move-right (action) ())
(defclass jump (action) ())

(defclass entity ()
  ((action :type action :initform (make-instance 'idle))))

(defgeneric perform-update (entity action))
(defmethod perform-update ((entity entity) (action idle)))
(defmethod perform-update ((entity entity) (action move-right))
  ;; Move right
)
(defmethod perform-update ((entity entity) (action jump))
  ;; Jump
)

(defgeneric on-update (entity))
(defmethod on-update ((entity entity))
  (perform-update entity (slot-value entity 'action)))


Before some LISPPER gets offended, I want to write: of course, it would look cleaner with eql specialisers or functions, but I assume Java doesn't have that.

Name: 7 2012-08-09 11:14

>>6
Damn, I took me way too much time to write this.

Name: Anonymous 2012-08-09 11:30

I see no code other than >>6 and >>7.

Name: Anonymous 2012-08-09 15:02

>>6
abstract class SimpleEntity implements IEntity
PIG DISGUSTING

Name: Anonymous 2012-08-09 17:28

>>7
(defclass jump (action) ())
Uh... Seriously?

Name: 7 2012-08-09 17:52

>>11
What's the problem?

Name: 7 2012-08-09 17:54

(I know that inheritance is useless here.)

Name: Anonymous 2012-08-09 23:05

>>8
Wow, we wrote basically the same thing when neither of us had seen the other yet.

>>13
It would work without but only because of lisp being lisp. If there was static typing it would be necessary to provide a root class that all actions inherit from so that you would have a name for their collective type.

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-08-10 6:21

Java bytecode has a direct indexed jump instruction which is what a switch would compile to.

The JIT should be able to compile that to an indirect jump, so your initial solution would be the most efficient.

>>6
This is the verbose (and "OOP") way to do it, taking advantage of the fact that you can have variables of class type and storing different objects with methods in them, but I recommend against that unless those actions have their own independent state.

But if you really want to use function pointers, switch to a language that has them!

Name: Anonymous 2012-08-10 11:54

Here's a joke!
``I want to learn Java, but I don't know where to start. Any pointers?''
Hah, got it? POINTERS

Name: Anonymous 2012-08-10 14:44

NU
RU
FUCKING
PO

Name: Anonymous 2012-08-10 15:36

>>17
GAH

Name: Anonymous 2012-08-10 19:34

>>15
this

no switch implementation uses conditional jumping so all this discussion was pointlesssigh...

Name: Anonymous 2012-08-11 1:20

>>15

yeah, the entity can be passed as a parameter instead. This allows for the action to be stateless and statically initialized and shared. So changing an objects action is just reassigning a reference rather than creating a new object.


interface IAction {
  void act(IEntity action);
}

interface IEntity {
  void idle();
  void jump();
  void moveRight();
}

class ActionIdle implements IAction {
  public void act(IEntity subject) {
    subject.idle();
  }

  static ActionIdle instance = new ActionIdle();
}

class ActionJump implements IAction {
  public void act(IEntity subject) {
    subject.jump();
  }

  static ActionJump instance = new ActionJump();
}

class ActionMoveRight implements IAction {
  public void act(IEntity subject) {
    subject.moveRight();
  }

  static ActionMoveRight instance = new ActionMoveRight();
}


abstract class SimpleEntity implements IEntity {
  private IAction currentAction;

  SimpleEntity(IAction currentAction) {
    this.currentAction = currentAction;
  }

  public void onUpdate() {
    currentAction.act(this);
  }

  public IAction getAction() {
    return currentAction;
  }

  public void setAction(IAction newAction) {
    this.currentAction = newAction;
  }
}

class Dog extends SimpleEntity {
  private String name;
  private float gender; // 0.0 - 1.0 with 0 being male and female being 1.0

  Dog(IAction currentAction, String name, float gender) {
    super(currentAction);
    this.name = name;
    this.gender = gender;
  }

  public void idle() {
    System.out.println(name + " scratches " + genderString() + "self");
    setAction(ActionJump.instance);
  }

  public void jump() {
    System.out.println(name + " looks up and takes a leap");
    setAction(ActionMoveRight.instance);
  }

  public void moveRight() {
    System.out.println(name + " pants and moves to the right");
    setAction(ActionIdle.instance);
  }

  private String genderString() {
    if(gender <= .01f) {
      return "him";
    } else if(gender <= .3f) {
      return "hem";
    } else if(gender <= .7f) {
      return "ey";
    } else if(gender <= .99f) {
      return "er";
    } else {
      return "her";
    }
  }
}


class Main {
  public static void main(String[] args) {
    Dog xe = new Dog(ActionIdle.instance, "xe", .6f);
    int moments = 10;
    for(int moment = 0; moment < moments; moment++) {
      xe.onUpdate();
    }
  }
}

Don't change these.
Name: Email:
Entire Thread Thread List