discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [objc-improvements] Just remembered something about multiple method


From: David Ayers
Subject: Re: [objc-improvements] Just remembered something about multiple method signatures...
Date: Sat, 06 Sep 2003 09:54:17 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

Ziemowit Laski wrote:

I guess my point is that arbitrarily picking a signature out of a pool
of contenders is fraught with problems, and I still believe that
the IMP fallback is a cleaner solution in this case.  I don't think
doing this breaks (codegen-wise) the counterexample you guys keep
discussing (i.e., where all the candidate methods return NSComparisonResult),
does it?

It doesn't on my architecture and probably not on the G4, but it would on 64 bit archs where small enums (i.e. NSComparisionResult) are not the same size as id (I'm not sure how the G5 handles small enums). In fact it would probably turn into an outright compile time error. I just liked that example because it wasn't constructed. (i.e. NSDate, NSString and NSNumber have different prototypes for '-compare:'.)

But maybe I can offer a more constructed example based on the promotions caused by IMP that shows the issue on all architecures and that given the intensive use of float with NSView subclasses in OPENSTEP derivatives, make it a valid one. I've attached an excerpt of a test we're preparing for contribution.

Given
Class1: -(id)test1Float:(float)f int:(int)i;
Class2: -(Object *)test1Float:(float)f int:(int)i;

In the old case, you could get a warning about the compiler picking the wrong prototype but the results were correct. But the new IMP promotion for id typed receivers will promote them to doubles and clobber not only of the float but all following arguments as well

I think that your suggestion about itteratively comparing the return value and then the arguments before falling back to varadic processing might be a good solution, as long as 'compatible' return values/arguments are "merged" to a general type (such as id/class) before falling back to varadic processing. (The warnings should remain, and if you like, with a flag to turn them off :-) )

Cheers,
David

/* Test varadic promotions. */
/* Contributed by David Ayers <d.ayers@inode.at>  */
/* fnear and dnear taken from previos tests.  */
/* { dg-options "-lobjc" } */
/* { dg-do run } */

#include <objc/Object.h>
#include <limits.h>

extern void abort(void);

#define CHECK_IF(expr) if(!(expr)) abort();

#define FLT_VAL 3.1
#define INT_VAL 1

int
fnear (float x, float y)
{
  float t = x - y;
  return t == 0 || x / t > 1000000.0;
}

int
dnear (double x, double y)
{
  double t = x - y;
  return t == 0 || x / t > 100000000000000.0;
}

@interface Class1 : Object
-(id)test1Float:(float)f
            int:(int)i;
-(void)test2Float:(float)f
              int:(int)i;
@end

@implementation Class1
-(id)test1Float:(float)f
              int:(int)i
{
  if (i==1)
    {
      CHECK_IF (fnear(f, FLT_VAL));
      CHECK_IF (i == INT_VAL);
    }
  else
    {
      printf("f:%f i:%i\n",f,i);
    }
  return nil;
}
-(void)test2Float:(float)f
              int:(int)i
{
  if (i==1)
    {
      CHECK_IF (fnear(f, FLT_VAL));
      CHECK_IF (i == INT_VAL);
    }
  else
    {
      printf("f:%f i:%i\n",f,i);
    }
}
@end

@interface Class2 : Object
-(Object *)test1Float:(float)f
                  int:(int)i;
-(void)test2Float:(double)f
              int:(int)i;
@end

@implementation Class2
-(Object *)test1Float:(float)f
             int:(int)i
{
  if (i==1)
    {
      CHECK_IF (fnear(f, FLT_VAL));
      CHECK_IF (i == INT_VAL);
    }
  else
    {
      printf("f:%f i:%i\n",f,i);
    }
  return nil;
}
-(void)test2Float:(double)f
              int:(int)i
{
  if (i==1)
    {
      CHECK_IF (dnear(f, FLT_VAL));
      CHECK_IF (i == INT_VAL);
    }
  else
    {
      printf("f:%f i:%i\n",f,i);
    }
}
@end

main()
{
  Class1 *varClass1;
  Class2 *varClass2;
  id      varId;

  varClass1 = [Class1 new];
  varClass2 = [Class2 new];

  [varClass1 test1Float:FLT_VAL int: 1];
  [varClass2 test1Float:FLT_VAL int: 1];
  [varClass1 test2Float:FLT_VAL int: 1];
  [varClass2 test2Float:FLT_VAL int: 1];

  /* Passing non-1 will print values instead of asserting them.  
     But note that in some cases the second argumen will be
     clobbered anyway. */
  /* Regression: Could be fixed by selection/merge */
  varId = varClass1;
  [varId test1Float:FLT_VAL int: 2]; 

  /* Regression: Could be fixed by selection/merge */
  varId = varClass2;
  [varId test1Float:FLT_VAL int: 2];

  /* Either this will fail... */
  varId = varClass1;
  [varId test2Float:FLT_VAL int: 2];

  /* ... or this will fail, depending on protoype selction.  */
  varId = varClass2;
  [varId test2Float:FLT_VAL int: 2];

  exit (0);
 
}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]