Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Java to Objective-C & OO Principles

Java to Objective-C & OO Principles
Thread Tools
Fresh-Faced Recruit
Join Date: Sep 2002
Status: Offline
Reply With Quote
Sep 15, 2002, 03:37 PM
 
I'm very familiar with Java and have a reasonable understanding of a good amount of the material covered by Design Patterns (GOF). Design Patterns suggests that code should always be written against an interface as opposed to an implementation. In Java, there is a formal construct known as an interface which can be implemented by any number of classes. When writing Java code, I usually ensure that my objects are accessed via methods declared in an interface. (For instantiation, I favor factories per interface type that invoke specific concrete constructors.)

However, Objective-C is an entirely new language for me. It seems that the analog to the interface in Java is the protocol in Objective-C. (I realize that Objective-C also has interfaces, but it seems these constructs can only be implemented by 1 class.) So, in keeping with the notion that I should code against an interface as much as possible, does it make sense for me to restrict my code to only work with protocols in Objective-C? (Perhaps I could also make factories to allocate and initialize against concrete classes.) The ability to avoid the use of static typing also has me wondering if the whole question of programming to an interface could be a moot point.

Also, I noticed some discussions about prefixes for Objective-C class names. It seems that there isn't really a prevailing standard. In Java, there are package names which serve as a sort of name space; they usually start with the primary domain of the author and then include additional parts that indicate the purpose of the class. For instance, com.blizzard.physics.Force might indicated a class written by Blizzard that represents a force that could be applied to a physical object. Would it be considered horribly sick and wrong if I were to prepend my classes using some similar sort of convention? I just keep thinking that GRPClass isn't going to cut it.
     
Mac Elite
Join Date: Feb 2001
Location: Vancouver, WA
Status: Offline
Reply With Quote
Sep 15, 2002, 07:05 PM
 
Read Object-Oriented Programming and the Objective-C Language (installed with the Developer Tools, or on Apple's site) for a good perspective on ObjC design patterns.

What I believe Design Patterns suggests is not "you should use the language feature called an interface"; instead, they're talking about how it's important to separate a class' interface from its implementation. The analogy the Apple book likes to use is of an analog clock: you can read the time on a clock's face without having to care whether the hands are driven by a pendulum, a coiled spring, or an oscillating quartz crystal. Likewise, when you use an NSMutableArray instance, you can addObject: and get objectAtIndex: without caring whether Apple has implemented array storage using a C array, a linked list, or an army of munchkins.

In ObjC, this corresponds to the common practice of declaring methods in an @interface block in a separate header file, and implementing methods in an @implementation block in a .m file. (If you choose, you can also follow the common convention of declaring additional internal-only methods within the .m file using a category.) This lets you build a program out of several classes by using their mutually-known interfaces, while retaining the ability to make improvements to one module without affecting the operation of others.

Protocols, on the other hand, are generally used when you want a further level of abstraction: allowing any class to be used for a given purpose, no matter what instance variables it has, no matter what it inherits from, so long as it responds to certain messages. For example, in the Omni apps' Find/Replace architecture, any object (be it an actual control like a text box or the controller object that maintains a table view or some such) can be a target for Find/Replace operations, so long as it responds to the methods in the find target protocol.
Rick Roe
icons.cx | weblog
     
gpack  (op)
Fresh-Faced Recruit
Join Date: Sep 2002
Status: Offline
Reply With Quote
Sep 16, 2002, 07:43 PM
 
I searched for "Object-Oriented Programming and the Objective-C Language" on Apple's site. Many links with this exact phrasing were returned. Unfortunately, they all point to a document titled Inside Mac OS X The Objective-C Programming Language. I've already read this one Is this different than the document that you were suggesting?

While I don't interpret the GOF suggestion to mean that one should code against the language feature known as an interface, I do believe that the basic level of abstraction that they are getting at, in terms of Objective-C, is at the level of a protocol. It seems that you, on the other hand, think that the level of abstraction is more on par with the Objective-C interface.

The reason I disagree is because it seems that the GOF book goes to great lengths to avoid the mention of a concrete class in code. In particular, the creational patterns focus on isolating the knowledge of the concrete class as much as possible such that even the name of the class is not known outside of the pattern.

In Objective-C, if I code against an interface X, sure, there are many scenarios where I can make changes to the implementation of X without having to change any of my other code. However, the problem arises when I want to swap X out for Y. To do this, I have to go through my entire code base and change every mention of X to Y. On the other hand, if X and Y both conform to the protocol Q, I can simply write my code to use Q and have a factory create something that conforms to Q (be that X, Y, Z, or whatever).

I think that the Apple document on the Objective-C programming language misrepresents the purpose of an Objective-C interface. It seems to simply be a necessity for the compiler as opposed to an implementation-neutral OOP construct.

By the way, Omni's applications are pretty sweet I take it you have a part in building them. If so, thanks!
     
Dedicated MacNNer
Join Date: Mar 2001
Location: Iowa City, IA
Status: Offline
Reply With Quote
Sep 17, 2002, 01:07 PM
 
I'd have to agree with gpack. The @interface provides a class-level abstraction that allows you to change the plumbing around at that level, but design patterns are an attempt at a more generic programming. So Objective-C protocols would map to what the Design Patterns authors call interfaces.
James

"I grew up. Then I got better." - Sea Wasp
     
Mac Elite
Join Date: Feb 2001
Location: Vancouver, WA
Status: Offline
Reply With Quote
Sep 17, 2002, 03:37 PM
 
Yeah, those two ObjC titles are the same book.

On the one hand, you're probably correct that what the GOF book refers to maps to protocols in ObjC. On the other hand, I'm not sure their advice still applies -- that book is sort of language-neutral, but it does assume a few things that don't apply in ObjC. With no static typing or binding requirements, you don't have to worry as much about tying yourself to concrete classes.

Using formal protocols is but one solution to your X, Y, Z and Q problem. Another commonly used one is class clusters: when you call initWithCapacity: on a freshly allocated NSMutableArray instance, it returns an instance of any of several private subclasses. NSMutableArray is actually an abstract class which chooses a concrete subclass based on what you ask it to do. (Note that in ObjC, abstract classes aren't so much a language restriction as a runtime one.)

Basically, the advice here is that you don't necessarily need to use protocols as much in ObjC as you might have used interfaces in Java, because ObjC only cares about static typing if you want it to. If you're in a situation where you can use any class for a variable, you can declare it as id, or as a common superclass, and use -respondsToSelector: or +instancesRespondToSelector: to test for functionality. Maintaining @protocol headers can be useful in many situations, but you're making yourself too much extra work if you're declaring them for every other class you create.
Rick Roe
icons.cx | weblog
     
gpack  (op)
Fresh-Faced Recruit
Join Date: Sep 2002
Status: Offline
Reply With Quote
Sep 17, 2002, 11:25 PM
 
I can see that writing everything to conform to a protocol could be a lot of work; and I have to admit that in Java, making everything implement an interface can be a little ritualistic.

The class clustering approach seems pretty cool. I suppose that I shied away from that approach because I am rather leery of inheritance. For a couple of years, I made these massive hierarchies of inheritance trees. Then I found out how woefully inflexible they were when things had to change. I suppose the GOF and other books also helped me cement my suspicion of inheritance. However, I could maybe see myself using it in Objective-C if the superclass had no meaningful implementation. Perhaps I am too cautious concerning inheritance.

The other approach of using references that are not statically typed is very appealing. Unfortunately, it seems to break down in 2 places. First, as you say, I would need to check every time to see if the untyped id could handle the message I was trying to send. In order to avoid rendundacy, I would imagine that I would have to create a generic invocation utility method that every call would pass through. That seems a little nasty. Otherwise, if I didn't check and sent a message to an object that couldn't handle it, the whole application would come crashing down around my ears. (If Objective-C had exceptions that could be thrown and caught, this problem might be obviated.)

The second problem deals with object instantiation. If I go so far as to not use static types, I surely wouldn't invoke specific allocate and init messages in ordinary code. Rather, I'd put these sorts of things in a factory. However, what the heck would I call the factory--IDFactory? What would the factory methods be called--createFunkyThing, createNormalThing, etc. Surely it would be silly to have 1 factory responsible for all classes of object. So how would I divide it? Perhaps I could have a ProtocolXFactory that returned id's conforming to X. I'm still chewing over this one.

Between coding to an interface, avoiding inheritance, avoiding redundancy, static typing, and dynamic binding, I am in a bit of a quandry . Ah well, hopefully with time and much more advice I will be able to choose more wisely. Thanks for entertaining my questions.
     
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status: Offline
Reply With Quote
Sep 17, 2002, 11:50 PM
 
Actually, in Objective-C, your program does NOT necessarily come crashing down if you call a nonexistent selector (method). There is an exception raised, but it can be ignored. In practice, it's not that difficult to keep up with which classes are being used and which ones support which function calls.

The className selector returns an NSString that includes the name of the class. There is also the isa selector, but I haven't figured that one out yet, as className works fine:

if ([[object className] isEqual: @"theClassIWant])
{
do some stuff
}

There are also more abstract methods of coding that could get around much usage of these functions.

NSObject is the root class as defined by Cocoa that takes care of many of your concerns. If you DO need to subclass the generic class, this would be the one to subclass. You wouldn't want to reimplement the stuff it implements for you.

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
     
Mac Elite
Join Date: Feb 2001
Location: Vancouver, WA
Status: Offline
Reply With Quote
Sep 18, 2002, 12:32 AM
 
If I go so far as to not use static types, I surely wouldn't invoke specific allocate and init messages in ordinary code.
Yikes. You've really been reading too many C++ books.

For one thing, I don't think I've ever seen a class that overrides +alloc, as the root class' implementation does a fine job of that for everybody.

Second, when you call -init, you're not necessarily tying yourself to a specific implementation. Method signatures aren't function pointers that correspond to specific implementations; they're messages. Calling -init is saying "hey, you, mister freshly allocated object, go ahead and do whatever initial setup you need in order to do your job, and give me a pointer to yourself when you're ready to receive other messages." It doesn't matter who or what is receiving the message so long as it returns a ready object (which actually doesn't have to be the object that received the -init message... that's how class clusters work).

Really, don't try to program Objective-C like it's C++. Your programs will be limited and your frustration will be limitless. Try to approach Cocoa as if all you knew was plain-C -- the object model and standards of design will make a lot more sense on their own than when considered from the point of view of a dissimilar OO language. (Actually, another good idea might be to look into Smalltalk.)
Rick Roe
icons.cx | weblog
     
Grizzled Veteran
Join Date: Feb 2001
Location: Pittsburgh
Status: Offline
Reply With Quote
Sep 19, 2002, 12:28 PM
 
Originally posted by gpack:
I can see that writing everything to conform to a protocol could be a lot of work; and I have to admit that in Java, making everything implement an interface can be a little ritualistic.

The class clustering approach seems pretty cool. I suppose that I shied away from that approach because I am rather leery of inheritance. For a couple of years, I made these massive hierarchies of inheritance trees. Then I found out how woefully inflexible they were when things had to change. I suppose the GOF and other books also helped me cement my suspicion of inheritance. However, I could maybe see myself using it in Objective-C if the superclass had no meaningful implementation. Perhaps I am too cautious concerning inheritance.
Your suspicion of inheritance is understandable. Java's API is a notoriously-bad example of an object tree grown out of control. However, you will definately want to give inheritance a second chance in Obj-C/Cocoa. Its roll is greatly changed by Obj-C's dynamic typing/linking and various cocoa features like notification centers.

Problems with inheritance are usually indicative of poor or unsuitable object design. Thankfully, Obj-C's message passing syntax reinforces a superior mental model of object ineteraction. (IMHO) As someone else suggested, it may be useful to approach this with a clean OO slate. Cocoa and Obj-C certainly gave me a new perspective on program design.
     
Mac Enthusiast
Join Date: Nov 2001
Status: Offline
Reply With Quote
Sep 19, 2002, 07:33 PM
 
The className selector returns an NSString that includes the name of the class. There is also the isa selector, but I haven't figured that one out yet, as className works fine:

if ([[object className] isEqual: @"theClassIWant])
{
do some stuff
}
Using the isa variable is easy:
Code:
if ([object class] == [TheClassIWant class]) { // groove all night on }
And I'm sure you know that using isEqualToString: is faster than isEqual: when comparing two strings .
     
Mac Elite
Join Date: Sep 2000
Location: Edmond, OK USA
Status: Offline
Reply With Quote
Sep 20, 2002, 12:02 PM
 
Originally posted by Ibson:


Using the isa variable is easy:
Code:
if ([object class] == [TheClassIWant class]) { // groove all night on }
And I'm sure you know that using isEqualToString: is faster than isEqual: when comparing two strings .
This is precisely the type of thing I would want to avoid. If you are having any part of your application rely on type checking, then something is amiss. The whole reason to use interfaces or protocols or whatever is so that you can guarantee that any object you invoke the intended action on would be able to handle it.

I don't know about ObjC, but in Java if my design broke down into switching on the type I would get worried. That is exactly what makes me reluctant to embrace weakly-typed languages - if the selector is not checked until runtime then in order to test I must hit every single line of code with every single object that might potentially be sent in order to finish the compilers job of enforcing type correctness.

Anyway, this has been a really interesting thread so far - the first one I have read that actually makes me interested in learning ObjC.
     
Mac Elite
Join Date: Feb 2001
Location: Vancouver, WA
Status: Offline
Reply With Quote
Sep 20, 2002, 02:21 PM
 
That is exactly what makes me reluctant to embrace weakly-typed languages - if the selector is not checked until runtime then in order to test I must hit every single line of code with every single object that might potentially be sent in order to finish the compilers job of enforcing type correctness.
If you're feeling compelled to undertake dramatic measures to enforce static typing and binding, you're making extra work for yourself and destroying the benefits of dynamic typing and binding -- you might as well just use C++.

The point of dynamism isn't to make you have to worry about every line of code that you write doing what you thought it would. To that end, the ObjC compiler lets you type variables, method arguments, and method returns more strictly than is necessary -- at run time, everything's an id, but you can enforce typing at compile time to help make sure you're writing code that will do the correct thing at run time.

Unless something else modifies your code at run time, you can generally count on compile-time type constraints to be obeyed. If a method on MyCustomClass takes a parameter of type MyCustomOtherClass, whatever code you write that calls that methods will have to supply an object of the correct type -- that's not going to change into something unpredictable at run time, so you don't have to worry about writing said method to check the class of each parameter. And if something does modify the runtime environment (a loaded plugin or some kind of "haxie", for example), the burden is traditionally on the one messing with stuff to make sure it still works.

What dynamic typing does allow you to do is more easily use certain implementation-independent design patterns. Notifications, delegation, and the NSControl target/action architecture are three of the design patterns made possible by dynamism -- and they're also three of the reasons Cocoa is known for letting you do more with less code.
Rick Roe
icons.cx | weblog
     
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status: Offline
Reply With Quote
Sep 20, 2002, 04:28 PM
 
Originally posted by absmiths:


That is exactly what makes me reluctant to embrace weakly-typed languages - if the selector is not checked until runtime then in order to test I must hit every single line of code with every single object that might potentially be sent in order to finish the compilers job of enforcing type correctness.
Actually, the compiler does give warnings at compile time. All you have to do is look at the warnings. If you coded in such a way that an object is being sent a message that only one of its subclasses could handle, but you know that's the only subclass that would ever pop up there, then you can ignore the warning. It doesn't require significantly more testing of the product; it requires more planning. You have to be smart about those warnings.

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
     
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status: Offline
Reply With Quote
Sep 20, 2002, 04:33 PM
 
Originally posted by Ibson:


Using the isa variable is easy:
Code:
if ([object class] == [TheClassIWant class]) { // groove all night on }
And I'm sure you know that using isEqualToString: is faster than isEqual: when comparing two strings .
I've been learning Cocoa while working on my CS senior project. I was not aware of how to use isa. I've been doing virtually all of my learning from Apple's documentation--learning bits and pieces of the more useful tidbits along the way. I just recently stumbled across a need for this and implemented the first method I came across that would compile.

I've been hoping to get enough done by the time I graduate (December) to snab me a job with some high-profile Mac company out in Seattle. The time issue makes me take a few shortcuts. I'll get it all figured out eventually.

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 01:47 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2