Friday, January 2, 2009, 05:35 PM -
Programming & ComputersPosted by Administrator
This is the first article of an occasional series.In my (very) recent post about programming for fun again, I had mentioned I would post about the differences between REALbasic and Objective-C with Cocoa. I just finished an exercise that I feel really shows off the differences between the two and also shows off just how fun these Project Euler questions are. The reason why I'm doing this is because there are several people on the forums who are curious about Cocoa, and my working on the Project Euler questions presents a good opportunity to show off each language.
DisclaimersThis (hopefully) series of articles assumes a basic knowledge of REALbasic or Objective-C with Cocoa. I will not dig into syntax or memory management in Cocoa because both topics have been discussed on other sites already.I am only just beginnging to learn Cocoa, so I'm sure the solutions I put forth are not the most efficient. However, based on what limited knowledge I have, I was able to solve the problem with reasonable effort. These problems can all be solved in different ways; a user can make them as simple or as complex as thay would like. I chose to make them as simply as I could to figure them out. You may, and probably will, decide to do it differently. Finally, this is not to start a langauge religious war. While I do editorialize in the articles a bit, I have no brand loyalty in the end and I am equal opportunity criticizer. If either REALbasic or Objective-C with Cocoa does something stupid, I'll point it out and laugh. If I do something stupid, I will have learned something from it.Euler Project Problem 2 Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
Find the sum of all the even-valued terms in the sequence which do not exceed four million.
I sorted out two ways to solve this problem, one with an array and one without. Let's go over the one without an array just to get familiar with the problem. In all cases, the solution runs within a function called RunProblem that returns an interger of the solution.
REALbasic
Function RunProblem() As Integer
dim theSolution as integer = 0
dim valueNminus2 as integer = 1
dim valueNminus1 as integer = 2
dim valueN as integer = valueNminus1 + valueNminus2
dim maxValue as integer = 4000000
// initialize the solution
theSolution = 2
// iterate the sequence to start things off
valueNminus2 = valueNminus1
valueNminus1 = valueN
// go through the rest of the sequence
while valueN < maxValue
// do the math
valueN = valueNminus1 + valueNminus2
// apply the number to theSolution if it qualifies
if valueN mod 2 = 0 then
theSolution = theSolution + valueN
end if
// iterate the sequence
valueNminus2 = valueNminus1
valueNminus1 = valueN
wend
return theSolution
End Function
Objective-C
- (int)RunProblem
{
int theSolution = 0;
int valueNminus2 = 1;
int valueNminus1 = 2;
int valueN = valueNminus1 + valueNminus2;
int maxValue = 4000000;
// initialize the solution
theSolution = 2;
// iterate the sequence to start things off
valueNminus2 = valueNminus1;
valueNminus1 = valueN;
// go through the rest of the sequence
while (valueN < maxValue) {
// do the math
valueN = valueNminus1 + valueNminus2;
// apply the number to theSolution if it qualifies
if (valueN % 2 == 0) {
theSolution += valueN;
}
// iterate the sequence
valueNminus2 = valueNminus1;
valueNminus1 = valueN;
}
return theSolution;
}
Nothing too fancy here. Both are easily readable, though the Objective-C is really just C in this instance and I'm reminded why I like REALbasic more: no brackets or semi-colons. I do understand
why they exist, however, and live with them accordingly.
However, I figured out the array method first and then rethought the non-array method after a quick session of playing the drums. Let's take a look at the array method...
REALbasic (This is a line by line port of the Objective-C code below for comparison)
Function RunProblem() As Integer
dim theSolution as integer = 0
dim FibonacciSequence(-1) as integer
dim FibonacciValue1 as integer = 1
dim FibonacciValue2 as integer = 2
FibonacciSequence.Append(FibonacciValue1)
FibonacciSequence.Append(FibonacciValue2)
dim maxValue as integer = 4000000
dim theValue as integer = 0
while theValue < maxValue
dim lastIndex as integer = UBound(FibonacciSequence)
dim valueNminus1 as integer = FibonacciSequence(lastIndex)
dim valueNminus2 as integer = FibonacciSequence(lastIndex - 1)
theValue = valueNminus1 + valueNminus2
FibonacciSequence.Append(theValue)
wend
for each mValue as integer in FibonacciSequence
if mValue mod 2 = 0 then
theSolution = theSolution + mValue
end if
next
return theSolution
End Function
Objective-C with Cocoa
- (int)RunProblem
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int theSolution = 0;
NSMutableArray *FibonacciSequence;
FibonacciSequence = [[NSMutableArray alloc] init];
NSNumber *FibonacciValue1;
FibonacciValue1 = [[NSNumber alloc] initWithInt:1];
NSNumber *FibonacciValue2;
FibonacciValue2 = [[NSNumber alloc] initWithInt:2];
[FibonacciSequence addObject:FibonacciValue1];
[FibonacciSequence addObject:FibonacciValue2];
int maxValue = 4000000;
int theValue = 0;
while (theValue < maxValue) {
NSNumber *lastIndex;
lastIndex = [[NSNumber alloc] initWithInt:[FibonacciSequence count]];
int valueNminus1;
valueNminus1 = [[FibonacciSequence objectAtIndex:[lastIndex intValue] - 1] intValue];
int valueNminus2;
valueNminus2 = [[FibonacciSequence objectAtIndex:([lastIndex intValue] - 2)] intValue];
theValue = valueNminus1 + valueNminus2;
if (theValue < maxValue) {
NSNumber *FibonacciValueN;
FibonacciValueN = [[NSNumber alloc] initWithInt:theValue];
[FibonacciSequence addObject:FibonacciValueN];
NSNumber *newLastIndex;
newLastIndex = [[NSNumber alloc] initWithInt:[FibonacciSequence count]];
}
}
for (NSNumber *valueToAdd in FibonacciSequence) {
if ([valueToAdd intValue] % 2 == 0) {
theSolution = theSolution + [valueToAdd intValue];
NSLog(@"%i", theSolution);
}
}
[pool drain];
return theSolution;
}
Okay, it's a little messy but the difference is apparent nonetheless.
Arrays in Cocoa, at least on the surface, are a hassle. If I want the same basic functionality in arrays that I'm used to in REALbasic, then I have to use
NSMutableArray, and that brings a whole lot of complexity to the table. Initializing
NSMutableArray is like any other object, but it's the appending values to it where the hassles begin. In the REALbasic code, I declared an array of
Integer type and appended two declared integers to the array, shown here:
dim FibonacciSequence(-1) as integer
dim FibonacciValue1 as integer = 1
dim FibonacciValue2 as integer = 2
FibonacciSequence.Append(FibonacciValue1)
FibonacciSequence.Append(FibonacciValue2)
In Objective-C, I can't just add on a couple of
int to the array because
NSMutableArray only takes objects. If I create an
int and send the
addObject message to the array, Xcode returns "
passing argument 1 of 'addObject:' makes pointer from integer without a cast". I'm cool with that because an
int isn't an object and I don't know how to cast (Yet). In looking up Integer in the documentation, I get back a number of results that
lead me to
NSNumber.
NSMutableArray *FibonacciSequence;
FibonacciSequence = [[NSMutableArray alloc] init];
NSNumber *FibonacciValue1;
FibonacciValue1 = [[NSNumber alloc] initWithInt:1];
NSNumber *FibonacciValue2;
FibonacciValue2 = [[NSNumber alloc] initWithInt:2];
[FibonacciSequence addObject:FibonacciValue1];
[FibonacciSequence addObject:FibonacciValue2];
On a side note, I tried
NSInteger, but that returned a lovely "
error: 'NSInteger' is not an Objective-C class name or alias". I later learned that
NSInteger isn't declared in the Cocoa or Foundation frameworks.
The other hassle came with I went to get the last item in the array. In REALbasic, this was done by the following:
dim lastIndex as integer = UBound(FibonacciSequence)
dim valueNminus1 as integer = FibonacciSequence(lastIndex)
Straightforward stuff.
Ubound returns a zero-based integer that I can then use to grab that item. Objective-C, on the other hand required the following:
NSNumber *lastIndex;
lastIndex = [[NSNumber alloc] initWithInt:[FibonacciSequence count]];
int valueNminus1;
valueNminus1 = [[FibonacciSequence objectAtIndex:[lastIndex intValue] - 1] intValue];
Right, well, it seems that the
count message for
NSMutableArray returns, if you can believe this, an
NSUInteger according to the documentation. However, if I use
NSUInteger, then I get the "error: 'NSUInteger' is not an Objective-C class name or alias". It seems
NSUInteger is also not declared in the Cocoa or Foundation frameworks. (So, how the hell did it make it into
NSMutableArray?)
I forget how I got to using
NSNumber as the datatype other than coming to the conclusion after reading the documenation that
NSNumber is a sort of "catch all" datatype for numbers (and
Boolean). What I feel is truly important here is notice how the
count message's NSUInteger get's set to the
NSNumber variable
without error and without any obvious casting. I didn't realize I did that until after I clicked "Build and Go".
The other small problem that I ran across is that the
count message returns a 1-based integer, but the indexes (indices?) require a 0-based integer. So, all of those folks (like me) who complain about a lack of 0- and 1-based inconsistency in REALbasic will quickly find the same thing in Objective-C.
The books I've been reading have all been saying that it's best to use the
NSObject-based objects in as many cases as possible. I'm sure there is someone out there saying that the Cocoa array way of doing this is better in the long run. I have yet to see how, but I'm sure long-term compatibility comes into play here. Regardless of that, I would much rather read the REALBasic code.
More problems will be written up if they offer up interesting language features.