Does Objective-C Support Mixin Like Ruby

Does Objective-C support Mixin like Ruby?

Edit: changes added because some people feel I am responsible for the limitations of Objective-C.

Short answer: you can't. Objective-C doesn't have the equivalent of Ruby mixins.

Slightly less short answer: Objective-C does have something with arguably the same flavour: protocols. Protocols (Interfaces in some other languages), are a way to define a set of methods an class that adopts that protocols is committing to implementing. A protocol doesn't provide an implementation though. That limitation prevents using protocols as an exact equivalent to Ruby mixins.

Even less short answer: However, the Objective-C runtime has an exposed API that lets you play with the dynamic features of the language. Then you step outside the language, but you can have protocols with default implementations (also called concrete protocols). Vladimir's answer shows one way to do that. At that point it seems to me you get Ruby mixins alright.

However, I am not sure I would recommend doing that. In most cases, other patterns fit the bill without playing games with the runtime. For example, you can have a sub-object that implement the mixed-in method (has-a instead of is-a). Playing with the runtime is OK, but has 2 drawbacks:

  • You make your code less readable as it requires readers to know a lot more than the language. Sure you can (and should) comment it, but remember that any necessary comment can be seen as an implementation defect.

  • You depend on that implementation of the language. Sure, Apple platforms are by far the most common ones for Objective-C but don't forget Cocotron or GnuStep (or Etoilé) which have different runtimes, which may or may not be compatible with Apple's on that respect.

As a side note, I state below that categories cannot add state (instance variables) to a class. By using the runtime API, you can lift that limitation too. This is beyond the scope of this answer however.

Long answer:

Two Objective-C features look like possible candidates: categories and protocols. Categories are not really the right choice here, if I understand the question properly. The right feature is a protocol.

Let me give an example. Suppose you want a bunch of your classes to have a specific ability called "sing". Then you define a protocol:

@protocol Singer
- (void) sing;
@end

Now you can declare that any of your own classes adopts the protocol the following way:

@interface Rectangle : Shape <Singer> {
<snip>
@end

@interface Car : Vehicle <Singer> {
<snip>
@end

By declaring that they adopt the protocol they commit themselves to implementing the sing method. For example:

@implementation Rectangle

- (void) sing {
[self flashInBrightColors];
}

@end

@implementation Car

- (void) sing {
[self honk];
}

@end

Then you use those classes for example like this:

void choral(NSArray *choir) // the choir holds any kind of singer
{
id<Singer> aSinger;
for (aSinger in choir) {
[aSinger sing];
}
}

Notice that the singers in the array don't need to have a common superclass. Notice also that a class can have only one superclass, but many adopted protocols. Notice finally that type checking is done by the compiler.

In effect, the protocol mechanism is multiple inheritance used for the mixin pattern. That multiple inheritance is severely limited because a protocol cannot add new instance variables to a class. A protocol only describes a public interface adopters must implement. Unlike Ruby modules it does not contain an implementation.

That's the most of it. Let's mention categories however.

A category is declared not in angle brackets, but between parenthesis. The difference is that a category can be defined for an existing class to expand it without subclassing it. You can even do so for a system class. As you can imagine, it's possible to use categories to implement something similar to mixin. And they were used that way for a long time usually as category to NSObject (the typical root of the inheritance hierarchy), to such an extent that they were called "informal" protocols.

It's informal because 1- no type checking is done by the compiler, and 2- implementing the protocol methods is optional.

There is no need today to use categories as protocols, especially because the formal protocols can now declare that some of their methods are optional with the keyword @optional or required (the default) with @required.

Categories are still useful to add some domain specific behavior to an existing class. NSString is a common target for that.

It's also interesting to point out that most (if not all) of NSObject facilities are in fact declared in a NSObject protocol. This means that it's not really compelling to use NSObject as a common superclass for all classes, though this is still commonly done for historical reasons, and well... because there is no drawback for doing so. But some system classes, such as NSProxy, are not NSObject.

How to achieve mixin or trait kind of behaviour in Objective C?

You may not need a Ruby Mixin for your specific case. You could create a new class that inherits from UIViewController and use that as the base class for your view controller classes that need this protocol.

If you want that protocol available in all your view controllers then you could use a category to extend the base class.

If you need the same implementation of the protocol for classes that are not descended from UIViewController then you really do need something like a Ruby Mixin. In that case, see this question describing how to use message forwarding. And this question has some related information in the answers.

The appropriate choice depends on the set of classes that need your implementation. If it is needed in some but not all UIViewController classes, use a subclass. If it is needed in all UIViewController classes but no others, use a category. Otherwise, use message forwarding.

Objective-C category compared to Mixins

To the best of my understanding:

Mixins

  • Syntactic sugar for composition
  • Added by the developer of the class, not the user
  • Can be reused by multiple classes
  • Can add instance variables
  • Can be implemented using forwarding in Objective-C

Categories

  • Similar to extension methods in other languages
  • Usually added by the user of the class, not the developer
  • Used by exactly one class and its subclasses
  • Can't add instance variables

Adding the same category to multiple classes

I'm still unaware of a clean way to do this in Objective-C, but with Swift 2.0 this can be implemented using Protocol Extensions by adding functions and/or properties to an existing protocol. The protocol can then be adopted by an arbitrary number of classes, structs, and/or enums.

protocol Numbered {
func number() -> Int
}

extension Numbered {
func number() -> Int {
return Int(arc4random()) % 10
}
}

class Book : Numbered {

}

class Chapter : Numbered {

}

class Page : Numbered {

}

let myBook = Book()
let myChapter = Chapter()
let myPage = Page()

print("myBook.number() = \(myBook.number())")
print("myChapter.number() = \(myChapter.number())")
print("myPage.number() = \(myPage.number())")

correctly implements number() on all three classes (Book, Chapter, Page):

myBook.number() = 5
myChapter.number() = 2
myPage.number() = 8

What is the difference between inheritance and Categories in Objective-C

Sometimes, inheritance just seems like more trouble than it is worth. It is correctly used when you want to add something to an existing class that is a change in the behaviour of that class.

With a Category, you just want the existing object to do a little more. As already given, if you just want to have a string class that handles compression, you don't need to subclass the string class, you just create a category that handles the compression. That way, you don't need to change the type of the string classes that you already use.

The clue is in the restriction that categories only add methods, you can't add variables to a class using categories. If the class needs more properties, then it has to be subclassed.(edit: you can use associative storage, I believe).

Categories are a nice way to add functionality while at the same time conforming to an object oriented principle to prefer composition over inheritance.

Edit January 2012

Things have changed now. With the current LLVM compiler, and the modern, 64-bit runtime, you can add iVars and properties to class extensions (not categories). This lets you keep private iVars out of the public interface. But, if you declare properties for the iVars, they can still be accessed / changed via KVC, because there is still no such thing as a private method in Objective-C.

What is the difference between an Abstract Class and a Mixin?

At a language-agnostic level, a mixin just adds functionality to a class, and is more for programmer convenience and to avoid code duplication. An abstract (base) class forms an is-a relationship and allows for polymorphism. One reason why inheritance is overused is that it's an easy way to implement mixins without writing any boilerplate in languages that don't really support them. The problem is that you're declaring a polymorphic is-a relationship as a side effect, making your API more confusing and possibly adding ambiguity. Hence, newer languages like D and Ruby support mixins as native features, allowing a convenient way to add a bunch of functionality to a class without declaring a polymorphic is-a relationship.

When adhering to Liskov Substitution Principle (LSP) can a child class implement additional interface?

The Liskov Substitution Principle has nothing to do with classes. It is about types. Ruby doesn't have types as a language feature, so it doesn't really make sense to talk about them in terms of language features.

In Ruby (and OO in general), types are basically protocols. Protocols describe which messages an object responds to, and how it responds to them. For example, one well-known protocol in Ruby is the iteration protocol, which consists of a single message each which takes a block, but no positional or keyword arguments and yields elements sequentially to the block. Note that there is no class or mixin corresponding to this protocol. There is no way for an object which conforms to this protocol to declare so.

There is a mixin which depends on this protocol, namely Enumerable. Again, since there is no Ruby construct which corresponds to the notion of "protocol", there is no way for Enumerable to declare this dependency. It is only mentioned in the introductory paragraph of the documentation (bold emphasis mine):

The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to sort. The class must provide a method each, which yields successive members of the collection.

That's it.

Protocols and types don't exist in Ruby. They do exist in Ruby documentation, in the Ruby community, in the heads of Ruby programmers, and in implicit assumptions in Ruby code, but they are never manifest in the code.

So, talking about the LSP in terms of Ruby classes makes no sense (because classes aren't types), but talking about the LSP in terms of Ruby types makes little sense either (because there are no types). You can only talk about the LSP in terms of the types in your head (because there aren't any in your code).

Okay, rant over. But that is really, really, really, REALLY important. The LSP is about types. Classes aren't types. There are languages like C++, Java, or C♯, where all classes are also automatically types, but even in those languages it is important to separate the notion of a type (which is a specification of rules and constraints) from the notion of a class (which is a template for the state and behavior of objects), if only because there are other things besides classes which are types in those languages as well (e.g. interfaces in Java and C♯ and primitives in Java). In fact, the interface in Java is a direct port of the protocol from Objective-C, which in turn comes from the Smalltalk community.

Phew. So, unfortunately none of this answers your question :-D

What, exactly, does the LSP mean? The LSP talks about subtyping. More precisely, it defines a (at the time it was invented) new notion of subtyping which is based on behaviorial substitutability. Very simply, the LSP says:

I can replace objects of type T with objects of type S <: T without changing the desirable properties of the program.

For example, "the program does not crash" is a desirable property, so I should not be able to make a program crash by replacing objects of a supertype with objects of a subtype. Or you can also view it from the other direction: if I can violate a desirable property of a program (e.g. make the program crash) by replacing an object of type T with an object of type S, then S is not a subtype of T.

There are a couple of rules we can follow to make sure that we don't violate the LSP:

  • Method parameter types are contravariant, i.e. if you override a method, the overriding method in the subtype must accept parameters of the same types or more general types as the overridden method.
  • Method return types are covariant, i.e. the overriding method in a subtype must return the same type or a more specific type as the overridden method.

These two rules are just the standard subtyping rules for functions, they were known long before Liskov.

  • Methods in subtypes must not raise any new exceptions that are not only raised by the overridden method in the supertype, except for exceptions whose types are themselves subtypes of the exceptions raised by the overridden method.

These three rules are static rules restricting the signature of methods. The key innovation of Liskov were the four behavioral rules, in particular the fourth rule ("History Rule"):

  • Preconditions cannot be strengthened in a subtype, i.e. if you replace an object with a subtype, you cannot impose additional restrictions on the caller, since the caller doesn't know about them.
  • Postconditions cannot be weakened in a subtype, i.e. you cannot relax guarantees that the supertype makes, since the caller may rely on them.
  • Invariants must be preserved, i.e. if the supertype guarantees that something will always be true, then it must also always be true in the subtype.
  • History Rule: Manipulating the object of a subtype must not create a history that is impossible to observe from objects of the supertype. (This one is a bit tricky, it means the following: if I observe an object of type S only through methods of type T, I should not be able to put the object in a state such that the observer sees a state that would not be possible with an object of type T, even if I use methods of S to manipulate it.)

The first three rules were known before Liskov, but they were formulated in a proof-theoretical manner which didn't take aliasing into account. The behavioral formulation of the rules, and the addition of the History Rule make the LSP applicable to modern OO languages.

Here is another way to look at the LSP: if I have an inspector who only knows and cares about T, and I hand him an object of type S, will he be able to spot that it is a "counterfeit" or can I fool him?

Okay, finally to your question: does adding the sneer_majesticly method violate the LSP? And the answer is: No. The only way that adding a new method can violate LSP is if this new method manipulates old state in such a way that is impossible to happen using only old methods. Since sneer_majesticly doesn't manipulate any state, adding it cannot possibly violate LSP. Remember: our inspector only knows about Animal, i.e. he only knows about walk and run. He doesn't know or care about sneer_majesticly.

If, OTOH, you were adding a method bite_off_foot after which the cat can no longer walk, then you violate LSP, because by calling bite_off_foot, the inspector can, by only using the methods he knows about (walk and run) observe a situation that is impossible to observe with an animal: animals can always walk, but our cat suddenly can't!

However! run could theoretically violate LSP. Remember: objects of a subtype cannot change desirable properties of the supertype. Now, the question is: what are the desirable properties of Animal? The problem is that you have not provided any documentation for Animal, so we have no idea what its desirable properties are. The only thing we can look at, is the code, which always raises a NotImplementedError (which BTW will actually raise a NameError, since there is no constant named NotImplementedError in the Ruby core library). So, the question is: is the raiseing of the exception part of the desirable properties or not? Without documentation, we cannot tell.

If Animal were defined like this:

class Animal
# …

# Makes the animal run.
#
# @return [void]
# @raise [NotImplementedError] if the animal can't run
def run
raise NotImplementedError
end
end

Then it would not be an LSP violation.

However, if Animal were defined like this:

class Animal
# …

# Animals can't run.
#
# @return [never]
# @raise [NotImplementedError] because animals never run
def run
raise NotImplementedError
end
end

Then it would be an LSP violation.

In other words: if the specification for run is "always raises an exception", then our inspector can spot a cat by calling run and observing that it doesn't raise an exception. However, if the specification for run is "makes the animal run or else raises an exception", then our inspector can not differentiate a cat from an animal.

You will note that whether or not Cat violates the LSP in this example is actually completely independent of Cat! And it is in fact also completely independent of the code inside Animal! It only depends on the documentation. That is because of what I tried to make clear in the very beginning: the LSP is about types. Ruby doesn't have types, so the types only exist in the programmer's head. Or in this example: in documentation comments.

Objective-C string manipulation

For fixed size concatenation, you can use [NSString stringWithFormat:] like:

NSString *str = [NSString stringWithFormat:@"%@ %@ %@",
@"Hello", @"World", @"Yay!"];


Related Topics



Leave a reply



Submit