Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
The sprite kit reference guide mentions the double dispatch pattern and refers to this wikipedia article.

It's not entirely clear to me how to implement this double dispatch pattern.
As far as I understand it: You have two objects. You call the first object with a reference to the second object as a parameter. You end up in a different function based on the type of the second object. Based on the function you are in, you call a method on the second object.

Some code should make it easier to understand. Suppose I have two custom classes A and B.
Keep in mind that you don't know (and don't have to know) which classes your objects have.
You also don't know which is the first or second object in the contact.

Code:
-(void) didBeginContact:(SKPhysicsContact *)contact
{
	SKNode *firstNode  = contact.bodyA.node;  //could be class A or B
	SKNode *secondNode = contact.bodyB.node; //could be class A or B
	[firstNode didBeginContact:contact
		  with:&secondNode];
}

implementation of A:
Code:
-(void) didBeginContact:(SKPhysicsContact *) contact
				   with:(ClassA **) node
{
 // class A with A contact => do nothing
}

-(void) didBeginContact:(SKPhysicsContact *) contact
		  with:(ClassB **) node
{
 // class A with B contact => reverse course of A and B
 [self reverseCourse];
  [*node reverseCourse]; 
}

implementation of B:
Code:
-(void) didBeginContact:(SKPhysicsContact *) contact
		   with:(ClassA **) node
{
 // class B with A contact => reverse course of A and B
  [self reverseCourse];
  [*node reverseCourse]; 
}

-(void) didBeginContact:(SKPhysicsContact *) contact
		   with:(ClassB **) node
{
 // class B with B contact => explode both objects
    [self explode];
    [*node explode];
}

But of course this code will not work because objective -c doesn't look at the argument types. It just sees twice didBeginContact:with: in both classes.

My question: how is double dispatch implemented? What am I missing here?
 

ChOas

macrumors regular
Nov 24, 2006
139
0
The Netherlands
Would examining the classtype within the function work for you ?

Example for your class A
Code:
-(void) didBeginContact:(SKPhysicsContact *) contact
				   with:(id *) node {
 if ([*node isMemberOfClass:[ClassB class]]) 
 {
   [self reverseCourse];
   [*node reverseCourse]; 
 }
}
 

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
Would examining the classtype within the function work for you ?

Example for your class A
Code:
-(void) didBeginContact:(SKPhysicsContact *) contact
				   with:(id *) node {
 if ([*node isMemberOfClass:[ClassB class]]) 
 {
   [self reverseCourse];
   [*node reverseCourse]; 
 }
}

Doesn't that go against the double dispatch pattern?
It's not that I can't hack together something functioning, I want to follow the correct principle.
 

ChOas

macrumors regular
Nov 24, 2006
139
0
The Netherlands
Doesn't that go against the double dispatch pattern?
It's not that I can't hack together something functioning, I want to follow the correct principle.

Hmmm. As far as I know (and please, anyone, correct me because I want to learn) you can't really do that within Objective-C.
 

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
Hmmm. As far as I know (and please, anyone, correct me because I want to learn) you can't really do that within Objective-C.

From the sprite kit programming guide:

"When your game needs to work with contacts, you need to determine the outcome based on both bodies in the collision. Consider studying the Double Dispatch Pattern and using it to farm out the work."

I kinda agree with you, but if the wizards at Apple mention this particular pattern then surely there is probably some way to do this that doesn't require introspection of the object?
 

ChOas

macrumors regular
Nov 24, 2006
139
0
The Netherlands
From the sprite kit programming guide:

"When your game needs to work with contacts, you need to determine the outcome based on both bodies in the collision. Consider studying the Double Dispatch Pattern and using it to farm out the work."

I kinda agree with you, but if the wizards at Apple mention this particular pattern then surely there is probably some way to do this that doesn't require introspection of the object?

Hmmm I just read those docs. And as for me I'm reading something like: "Don't let your scenecontroller/director figure everything out. But leave it to the objects themselves like using double dispatch."

Then again, that is just my interpretation :)
 
Last edited:

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
Maybe it's the visitor pattern that is supposed to be implemented.

This works and looks (relatively) elegant.

Code:
   NSLog(@"Hello, World!");
   ClassA *a = [[ClassA alloc] init];
		ClassB *b = [[ClassB alloc] init];
	 	[a acceptVisitor:a
					with:@"aa"];

		[a acceptVisitor:b
					with:@"ab"];
		
		
		[b acceptVisitor:a
					with:@"ba"];
		
		[b acceptVisitor:b
					with:@"bb"];


Class A:
Code:
-(void) acceptVisitor:(id) visitor
				 with:(id) contact
{
	[visitor didVisitClassA:self
					   with:contact];
}


-(void) didVisitClassA:(id) visited
				  with:(id) contact
{
	//visitor (=self) is classA, the visited is classA
	//=> do nothing
	NSLog(@"do nothing");
}

-(void) didVisitClassB:(id) visited
				  with:(id) contact
{
	//visitor (=self) is classA, the visited is classB
	[visited explodeWith:self];
}


//actions
-(void) reverseCourse:(id) contact
{
	NSLog(@"reverse A (%@)",contact);
}

Class B:
Code:
-(void) acceptVisitor:(id) visitor
				 with:(id) contact
{
	[visitor didVisitClassB:self
					   with:contact];
}

-(void) didVisitClassA:(id) visited
				  with:(id) contact
{
	//visitor (=self) is classB, the visited is classA
	//=> explose
	[self explodeWith:visited];
}


-(void) didVisitClassB:(id) visited
				  with:(id) contact
{
	//visitor (=self) is classB, the visited is classB
	//=> reverse course
	[self reverseCourse];
	[visited reverseCourse];
}

//actions
-(void) explodeWith:(id) missle
{
	NSLog(@"exploding");
}

-(void) reverseCourse
{
	NSLog(@"reverse B");
}
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.