[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Message forwarding...
From: |
Scott Christley |
Subject: |
Re: Message forwarding... |
Date: |
Wed, 19 Feb 1997 15:15:15 -0800 |
At 03:17 PM 2/19/97 +0000, Barry McMullin wrote:
>At 21:25 14/02/97 -0500, Wojtek Kopczuk <address@hidden> wrote:
>>I haven't seen an answer to your question yet so here it is:
>>you can implement message forwarding in GNU ObjC.
>>Having following method does a trick:
>>
>>-forward: (SEL) aSelector : (arglist_t) arguments {
>> return [ obj performv: aSelector : arguments];
>>}
>>
>>where 'obj' is an object to which method should be forwarded.
>
>I tried it and it works. It's not a very severe test because
>my forwarded messages all have trivial interfaces (at most an
>int argument, and an int return), but it does prove the principle.
Warning! Warning! Danger! Danger! (Wave your arms around) :-)
Forwarding is great an wonderful but there are definitely problems depending
upon what version of the ObjC runtime that you have in your GCC. The most
recent snapshot that I released back in 960906 still has a problem, so try
both of the programs to test; this only relates to i386 machines though as
far as I know.
The first program tests the problem with initialization of the floating
point stack; the second has to do with return floats/doubles from forwarded
methods.
*** test-double.m: test program ***
*/
#include <objc/Object.h>
@interface TestDouble : Object
+ (double) testDouble;
- (double) testDoubleInstance;
@end
@implementation TestDouble
+ (double) testDouble
{
return 123456789.0;
}
- (double) testDoubleInstance
{
return 987654321.0;
}
@end
int main()
{
double foo;
id bar;
foo = [TestDouble testDouble];
printf ("TestDouble 1st call is %f\n", foo);
foo = [TestDouble testDouble];
printf ("TestDouble 2nd call is %f\n", foo);
bar = [[TestDouble alloc] init];
foo = [bar testDoubleInstance];
printf ("testDouble is %f\n", foo);
}
/*
*** test-double.m: bad results ***
TestDouble 1st call is NaN
TestDouble 2nd call is 123456789.000000
testDouble is 987654321.000000
*/
/*
second program
the results of both runs should be identical
*/
#include <stdio.h>
#include <objc/Object.h>
@protocol test1
- init;
@end
@protocol test2
- free;
@end;
typedef struct _EightInt {
int one;
int two;
int three;
int four;
int five;
int six;
int seven;
int eight;
int nine;
int ten;
int eleven;
int twelve;
}TwelveInt;
@interface Dummy1:Object < test1, test2 >
{
}
- (float)anInt:(int)a timesInt:(int)b plusFloat:(float)f;
- (float)times3:(float)num;
- (int)times2:(int)num;
- (double)doubleTimes:(double)d1 :(double)d2;
- (float)floatTimes:(float)d1 :(float)d2;
- (float)float4:(float)f1 :(float)f2 :(float)f3 :(float)f4;
- (int)sumStructPtr:(TwelveInt *)aStruct;
- (TwelveInt)newStruct;
@end
@implementation Dummy1
// this was put in to test the debugger for valid values on break point
// for subroutine with float values
float twoFloatProduct(float a, float b)
{
float result = 0; // THis is a test
result = a;
result = result * b;
return result;
}
- init
{
return [super init];
}
- free
{
return [super free];
}
- (float)anInt:(int)a timesInt:(int)b plusFloat:(float)f
{
float fa = a;
float fb = b;
float ret;
ret = (fa * fb) + f;
return ret;
}
- (float)times3:(float)num
{
return twoFloatProduct(3.0, num);
}
- (int)times2:(int)num
{
return 2.0 * num;
}
- (double)doubleTimes:(double)d1 :(double)d2
{
double m;
m = d1 * d2;
return m;
}
- (float)floatTimes:(float)d1 :(float)d2
{
// these intermediate values are here to test the debugger
// without optimization to see if executed lines in method help
float result ;
result = d1 * d2;
return result;
}
- (float)float4:(float)f1 :(float)f2 :(float)f3 :(float)f4
{
return f1 * f2 * f3 * f4;
}
- (int)sumStructPtr:(TwelveInt *)aStruct;
{
return aStruct->one+aStruct->two+aStruct->three+aStruct->four+
aStruct->five+aStruct->six+aStruct->seven+aStruct->eight+
aStruct->nine+aStruct->ten+aStruct->eleven+aStruct->twelve;
}
- (TwelveInt)newStruct
{
TwelveInt st;
st.one = 1;
st.two = 2;
st.three = 3;
st.four = 4;
st.five = 5;
st.six = 6;
st.seven = 7;
st.eight = 8;
st.nine = 9;
st.ten = 10;
st.eleven = 11;
st.twelve = 12;
return st;
}
@end
@interface Dummy2:Object
{
id friend;
}
- setFriend:anObject;
@end
@implementation Dummy2
- setFriend:anObject
{
friend = anObject;
return self;
}
- (retval_t)forward:(SEL)aSelector :(arglist_t)argFrame
{
retval_t ret;
fprintf(stdout,"attempting to forward: ");
if ( [friend respondsTo:aSelector] )
{
ret = [friend performv:aSelector :argFrame];
return ret;
}
[self doesNotRecognize:aSelector];
}
@end
int runTestUsing(id testObj)
{
TwelveInt stru, nst;
double tf;
double pf;
int td;
tf = [testObj anInt:2 timesInt:3 plusFloat:4.3];
fprintf(stdout,"[testObj anInt:2 timesInt:3 plusFloat:4.3] = %f\n",tf);
tf = [testObj times3:9.0];
fprintf(stdout,"[testObj times3:9] =%f\n", tf);
td = [testObj times2:8];
fprintf(stdout,"[testObj times2:8] =%d\n", td);
pf = [testObj doubleTimes:20:4];
fprintf(stdout,"[testObj doubleTimes:20:4] =%lf\n", pf);
tf = [testObj floatTimes:20:4];
fprintf(stdout,"[testObj floatTimes:20:4] =%f\n", tf);
tf = [testObj float4:3.0 : 4.0 : 5.0 : 6.0];
fprintf(stdout,"float4:%5.2f:%5.2f:%5.2f:%5.2f = %f\n", 3.0, 4.0,
5.0, 6.0, tf);
stru.one = stru.two = stru.three = 100;
stru.four = stru.five = stru.six = 3;
stru.seven = stru.eight = 33 ;
stru.nine = stru.ten = stru.eleven = stru.twelve = 5 ;
td = [testObj sumStructPtr:&stru];
fprintf(stdout,"Sum of stuct pointer passed in = %d\n", td);
tf = [testObj times3: [testObj times3: 2]];
fprintf(stdout,"[testObj times3:[testObj times3: 2]] = %f\n", tf);
nst = [testObj newStruct];
fprintf(stdout, "[testObj newStruct] %d %d %d %d %d %d %d %d %d %d %d
%d\n",
nst.one, nst.two, nst.three, nst.four, nst.five, nst.six,
nst.seven, nst.eight, nst.nine, nst.ten, nst.eleven,
nst.twelve);
return 0;
}
int main (int argc, char *argv[])
{
id test1;
id test2;
test1 = [[Dummy1 alloc] init];
test2 = [[Dummy2 alloc] init];
fprintf(stdout, "\n\nrunning tests\n");
runTestUsing(test1);
//
//
// test forwarding
//
//
fprintf(stdout, "\n\nrunning tests using forwarding \n");
[test2 setFriend:test1];
runTestUsing(test2);
exit(0);
}