PDA

View Full Version : Exercise 9-4 Kochan 2.0. A question




mdeh
Jan 20, 2009, 07:45 AM
Based on the discussions about argument and return types in this chapter, modify both add: methods in the Fraction andComplex classes to take and return id objects. Then write a program that incorporates the following code sequence:
result = [dataValue1 add: dataValue2];
[result print];
where result, dataValue1, and dataValue2 are id objects. Make sure you set dataValue1 and dataValue2 appropriately in your program and free all objects before your program terminates.

Does this mean to modify EACH method so that EACH method can take a fraction or complex class object?



skochan
Jan 20, 2009, 09:37 AM
Does this mean to modify EACH method so that EACH method can take a fraction or complex class object?

The Complex and Fraction classes both have add: methods. The exercise is to change the argument and return type of each add: method to take and return an id object.

Cheers,

Steve K.

mdeh
Jan 20, 2009, 02:14 PM
Answer for 9-4???
Here is my attempt. Your input is appreciated.

Fraction.h


#import <Foundation/Foundation.h>
@interface Fraction : NSObject {
int numerator;
int denominator;
}
@property int numerator, denominator;
-(void) setTo: (int) n over: (int) d;
-(id) add: (id) f;
-(void) reduce;




#import "Fraction.h"


@implementation Fraction;
@synthesize denominator, numerator;
-(void) print
{

NSLog(@"%i/%i ", numerator, denominator);
}

-(void) setTo: (int) n over: (int) d
{
numerator = n;
denominator = d;
}


-(id) add: (id) f
{
int resultNum, resultDenom;
Fraction* result = [[Fraction alloc] init];

resultNum = numerator *[ f denominator] + denominator * [f numerator];
resultDenom = denominator *[ f denominator];

[result setTo: resultNum over: resultDenom];
[result reduce];
return result;
}

-(double) convertToNum
{
if (denominator != 0)
return (double) numerator / denominator;
else
return 1.0;
}

-(void) reduce
{
int u, v, temp;
BOOL isNegativeNumerator = NO;
BOOL isNegativeDenominator = NO;

if ( numerator < 0)
{
isNegativeNumerator = YES;
numerator = -numerator;
}


if ( denominator < 0)
{
isNegativeDenominator = YES;
denominator = -denominator;
}

u = numerator;
v = denominator;


while (v != 0) {
temp = u % v;
u = v;
v = temp;
}



numerator /= u;
denominator /= u;



if ( isNegativeNumerator == YES || isNegativeDenominator == YES)
numerator = -numerator;
}

@end


Complex.h


#import <Foundation/Foundation.h>

@interface Complex : NSObject
{
float real;
float imaginary;
}

@property float real, imaginary;
-(id) add: (id) complexNumber;
-(void) setReal: (float) r andImaginary: (float) i;
-(void) print;
@end

Complex.m


#import "Complex.h"
@implementation Complex

@synthesize real, imaginary;

-(void) setReal: (float) r andImaginary: (float) i
{
real = r;
imaginary = i;
}

-(id) add: (id) complexNumber
{
Complex *myCx = [[ Complex alloc ] init];
myCx.real = (real + [complexNumber real]);
myCx.imaginary = (imaginary + [complexNumber imaginary]);
return myCx;

}
-(void) print
{
NSLog(@"%g + %gi", real, imaginary);
}
@end


main.m


#import "Fraction.h"
#import "Complex.h"

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id dataVal1, dataVal2, result;
Complex *c1 = [[ Complex alloc] init];
Complex *c2 = [[ Complex alloc] init];
Fraction *f1 = [ [ Fraction alloc] init];
Fraction *f2 = [ [ Fraction alloc] init];

[c1 setReal: 67.0 andImaginary: 76.0];
[c2 setReal: 27.0 andImaginary: 72.0];
dataVal1 = c1;
dataVal2 = c2;

result = [dataVal1 add: dataVal2];
[result print];

[result release];

[f1 setTo: 4 over: 5];
[f2 setTo: 7 over: 8];

dataVal1 = f1;
dataVal2 = f2;

result = [ dataVal1 add: dataVal2];
[result print];
[result release];



[f1 release];
[f2 release];
[c1 release];
[c2 release];
[pool drain];
return 0;
}

TotalLuck
Jan 20, 2009, 05:45 PM
Thanks a ton. again i was about to ask for help and there you are posting.

After pulling my hair out i see what was perplexing me.

I was trying to use f.numerator instead of [ f numerator].

So if i understand it , the dot notation is used when you/program knows what to expect from the object that was passed in. The [ f numerator] is basically saying go get this item. ( i had tried [f getNumerator] )

i don't have a problem getting the program to compile using the following
from fraction .m
-(id) add: (id) f
{ //add fractions together

// result stores the reult of the addition


Fraction *result = [[Fraction alloc] init];
double resultNum, resultDenom , fnum ;

if ( f < 0)
{

fnum = -1 * [f numerator];
resultNum = numerator * [f denominator ] - denominator * fnum ;
resultDenom = denominator * [f denominator];
[result setTo:resultNum over: resultDenom];
}

else
{

resultNum = numerator * [f denominator ] + (denominator * [ f numerator ]);
resultDenom = denominator * [ f denominator ];
[result setTo:resultNum over: resultDenom];
}
if (resultNum > resultDenom)
{
[result reduce];

}

return result;

}

int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];

id result, dataValue2, dataValue1;
Fraction *f1 = [[Fraction alloc]init];
Fraction *f2 = [[Fraction alloc]init];
ComplexNumbers *c1 = [[ ComplexNumbers alloc] init];
ComplexNumbers *c2 = [[ ComplexNumbers alloc] init];

[f1 setTo:2 over:5];
[f2 setTo:5 over:8];

result = [ f1 add: f2];
[result print];


but when i add

dataValue1 = f1;
dataValue2 = f2;

result = [ dataValue1 add: dataValue2 ];
[result print];
[result release];

i get error
" - void value not ignored as it ought to be. "
what am i missing there?

mdeh
Jan 20, 2009, 06:25 PM
I was trying to use f.numerator instead of [ f numerator].


There clearly is a difference. Perhaps one of the more erudite contributors could clear this up?



i get error
" - void value not ignored as it ought to be. "
what am i missing there?[/QUOTE]



I am not sure if this would make any difference, but are you releasing "result" before you use it again?

skochan
Jan 20, 2009, 07:13 PM
Thanks a ton. again i was about to ask for help and there you are posting.

After pulling my hair out i see what was perplexing me.

I was trying to use f.numerator instead of [ f numerator].

So if i understand it , the dot notation is used when you/program knows what to expect from the object that was passed in.


That's right! The dot notation cannot be used directly on id variables (you'd have to typecast it first to the appropriate object type). I should have pointed that out in the text--and I'll get it into the next printing.


but when i add

dataValue1 = f1;
dataValue2 = f2;

result = [ dataValue1 add: dataValue2 ];
[result print];
[result release];

i get error
" - void value not ignored as it ought to be. "
what am i missing there?

Without seeing all the code, I'm guessing you have the add: method declared to return void somewhere (perhaps in the ComplexNumbers.h/.m files?). Let me know, or email the complete code to me.

Cheers,


Steve Kochan

TotalLuck
Jan 20, 2009, 07:40 PM
Here are the files
#import <Foundation/Foundation.h>
#import <objc/Object.h>

@interface Fraction : NSObject
{
int numerator;
int denominator;
}

@property int numerator, denominator;

-(void) print;
-(double) convertToNum;
-(void) setTo: (int) n over: (int) d;
-(id) add:(id) f;
-(Fraction *) subtract: (Fraction *) f;
-(Fraction *) multiply: (Fraction *) f;
-(Fraction *) divide: (Fraction *)f;
-(void) reduce;


@end


#import "Fraction.h"


@implementation Fraction
@synthesize numerator, denominator;

-(void) print
{
int whole, num2;
BOOL needToReduce;

if ( numerator >= denominator)
needToReduce = YES;


if (needToReduce == YES)
{
whole = numerator / denominator;
num2 = numerator % denominator;
if (numerator % denominator == 0)
NSLog(@" %i ", whole);
else
NSLog(@" %i %i/%i ", whole, num2, denominator);
}
else
NSLog(@" %i/%i ",numerator, denominator);
}

-(double) convertToNum
{

if ( denominator != 0 )
return (double) numerator / denominator;
else
return 1;
}

-(void) setTo: (int) n over: (int) d
{
numerator = n;
denominator = d;
}


-(id) add: (id) f
{ //add fractions together

// result stores the reult of the addition


Fraction *result = [[Fraction alloc] init];
double resultNum, resultDenom , fnum ;

if ( f < 0)
{

fnum = -1 * [f numerator];
resultNum = numerator * [f denominator ] - denominator * fnum ;
resultDenom = denominator * [f denominator];
[result setTo:resultNum over: resultDenom];
}

else
{

resultNum = numerator * [f denominator ] + (denominator * [ f numerator ]);
resultDenom = denominator * [ f denominator ];
[result setTo:resultNum over: resultDenom];
}
if (resultNum > resultDenom)
{
[result reduce];

}

return result;

}

-(Fraction *) subtract: (Fraction *) f
{
//subtract fractions
Fraction *result = [[Fraction alloc] init];
int resultNum1, resultNum2, resultDenom, resultNum;


if ( f < 0)
{
f.numerator = -1 * f.numerator;

resultNum1 =(numerator * f.denominator) ;
resultNum2 = (denominator * f.numerator);
resultDenom = (denominator * f.denominator);

resultNum = resultNum1 + resultNum2;

[result setTo:resultNum over: resultDenom];
}

else {

resultNum1 =(numerator * f.denominator) ;
resultNum2 = (denominator * f.numerator);
resultDenom = (denominator * f.denominator);

resultNum = resultNum1 - resultNum2;

[result setTo:resultNum over: resultDenom];
}

if (resultNum > resultDenom)
{
[result reduce];
}


return result;
}
-(Fraction *) multiply: (Fraction *) f
{
Fraction *result = [[Fraction alloc]init];
int resultNum, resultDenom;


if ( f < 0)
{
f.numerator = -1 * f.numerator;

resultNum = numerator * f.numerator;
resultDenom = denominator * f.denominator;

[result setTo:resultNum over: resultDenom];
}
else
{

resultNum = numerator * f.numerator;
resultDenom = denominator * f.denominator;

[result setTo:resultNum over: resultDenom];
}

if (resultNum > resultDenom)
{
result.reduce;
}

return result;
}


-(Fraction *) divide: (Fraction *)f
{
Fraction *result = [[Fraction alloc]init];
int resultNum, resultDenom;

resultNum = numerator * f.denominator;
resultDenom = denominator * f.numerator;

[result setTo:resultNum over: resultDenom];

if (resultNum > resultDenom)
{
result.reduce;
}


return result;
}



-(void) reduce
{
int u = numerator;

int v = denominator;
int temp;



while ( v != 0)
{
temp = u % v;
u = v;
v = temp;
}

numerator /= u;
denominator /= u;

}


@end



#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>


@interface ComplexNumbers : NSObject
{
double real;
double imaginary;
}

@property double real, imaginary;

// methods
-(void) setReal : (double) a andImaginary: (double) b;
-(void) print; // to print as a + b(i)
-(id) add: (id) c;




@end
#import "Complex.h"


@implementation ComplexNumbers

@synthesize real, imaginary;
// define methods
-(id) add: (id) c
{
id result = [[ComplexNumbers alloc] init];
double r1, imag1;

r1 = real + [c real];
imag1 = imaginary + [c imaginary];
[result setReal:r1 andImaginary:imag1];

return result;

}
-(void) setReal: (double) a andImaginary: (double) b
{
real = a , imaginary = b;
}

-(void) print // print the equation
{
NSLog(@"(%g + %gi)", real, imaginary);
}

@end
#import <Foundation/Foundation.h>
#import "Fraction.h"
#import "Complex.h"


int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];

id result, dataValue2, dataValue1;
Fraction *f1 = [[Fraction alloc]init];
Fraction *f2 = [[Fraction alloc]init];
ComplexNumbers *c1 = [[ ComplexNumbers alloc] init];
ComplexNumbers *c2 = [[ ComplexNumbers alloc] init];

[f1 setTo:2 over:5];
[f2 setTo:5 over:8];

result = [ f1 add: f2];
[result print];

dataValue1 = f1;
dataValue2 = f2;
result = [ dataValue1 add: dataValue2 ];

[result print];


[c1 setReal: 10 andImaginary: 2.5 ];
[c2 setReal: 14 andImaginary: 3];

result = [ c1 add: c2 ];
[result print];

dataValue1 = c1;
dataValue2 = c2;

result = [ dataValue1 add: dataValue2 ];

[result print];
[result release];

[c1 release];
[c2 release];
[f2 release];
[f1 release];
[pool drain];
return 0;


}

i am using Xcode leopard 10.5

here is the debug

/users/lori/Desktop/Objectve c lessons/Rectangle/main.m: In function 'main':
/Users/lori/Desktop/Objectve c lessons/Rectangle/main.m:32: warning: multiple methods named '-add:' found
/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSObjectController.h:59: warning: using '-(void)add:(id)sender'
/Users/lori/Desktop/Objectve c lessons/Rectangle/Fraction.h:22: warning: also found '-(id)add:(id)f'
/Users/lori/Desktop/Objectve c lessons/Rectangle/main.m:32: error: void value not ignored as it ought to be
/Users/lori/Desktop/Objectve c lessons/Rectangle/main.m:46: warning: multiple methods named '-add:' found
/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSObjectController.h:59: warning: using '-(void)add:(id)sender'
/Users/lori/Desktop/Objectve c lessons/Rectangle/Fraction.h:22: warning: also found '-(id)add:(id)f'
/Users/lori/Desktop/Objectve c lessons/Rectangle/main.m:46: error: void value not ignored as it ought to be


does it look like an error in the framework file?

skochan
Jan 20, 2009, 08:14 PM
/[B]Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSObjectController.h:59: warning: using '-(void)add: (id)sender'
[/CODE]
does it look like an error in the framework file?

Looks like the NSObjectController class has an add: method that returns void; thus the conflict at compile time. Use different method names (like addX). This goes back to the point made in the text about sending a message to an id type: all methods of the same name must agree in arguments and return type. This is actually a good learning exercise :D

By the way, you shouldn't be importing <objC/Object.h> . I don't have my book handy, but if that's from the text, it's a holdover from the first edition.

-----------
From Apple's documentation on the NSObjectController class:

add:
Creates a new object and sets it as the receiver’s content object.

- (void)add: (id)sender

Parameters
sender
Typically the object that invoked this method.
....

-------------

Cheers,

Steve Kochan

TotalLuck
Jan 21, 2009, 01:20 PM
By the way, you shouldn't be importing <objC/Object.h> . I don't have my book handy, but if that's from the text, it's a holdover from the first edition.


Yeah i forgot to delete that.. I worked through the first 5 chapters in Book 1 then got Book 2 and forgot to change some of the file #imports. so dont chase down the editor just yet.

and thanks for the help. changing to the -(id)addX fixed the problem.

mdeh
Jan 21, 2009, 03:12 PM
That's right! The dot notation cannot be used directly on id variables (you'd have to typecast it first to the appropriate object type). I should have pointed that out in the text--and I'll get it into the next printing.

Steve, I thought the "typecast" operator was () as in:

return (float) 7 /* where 7 is an int */

Here we use [ ..... ]. Could you elaborate a little.

Thank you.

skochan
Jan 21, 2009, 04:20 PM
Steve, I thought the "typecast" operator was () as in:

return (float) 7 /* where 7 is an int */

Here we use [ ..... ]. Could you elaborate a little.

Thank you.

Ahh, I was hoping you wouldn't ask me that. If you knew the id object f was a Fraction, you could write the following:


((Fraction *) f).numerator


I'm only showing you this because you asked. But it's ugly!

Cheers,

Steve Kochan