Oliver Cooper
Oliver Cooper

Reputation: 845

Why are NSRect, NSPoint, etc. structs, not classes?

I've recently needed to create my own type similar to NSRect that has an anchor point (essentially an NSRect with another NSPoint in it).

After some research I found that I was actually probably better off to just make this a class (as in NSObject subclass), rather than using struct. Why then has Apple make these types structs, not classes? It seems like it would have many benefits, such as not having to wrap them in NSValues, not have to use C functions to interact with them, etc.

I'm sure they'd have a reason. Is it simply the slightly less memory usage? Is it just historical? Or have I missed something bigger?

Upvotes: 17

Views: 2083

Answers (9)

Paolo
Paolo

Reputation: 15827

Why then has Apple make these types structs, not classes?

For performance reasons, as these entities are frequently used, frequently processed and small. And the overhead of having them encapsulated in objects is not justified by the advantages of them being objects.

Upvotes: 3

Nick Lockwood
Nick Lockwood

Reputation: 40995

The overriding reason is performance - all of Cocoa's performance-critical APIs (graphics, audio) tend to use C structs and functions for this sort of purpose.

The reasons are that these can much more easily be optimised by the C-compiler. C functions can be called more cheaply than methods, and they can be inlined automatically by the compiler, removing the function call overhead altogether. C structs are allocated on the stack instead of the heap, which means that processing can mostly be done in registers or low-level CPU caches instead of calling out to main memory, which is hundreds of times slower.

Cocoa methods are dynamically dispatched. They might be overridden by a subclass or swizzling, so the compiler cannot inline them because it can't be sure what they will do until they are executed at runtime. Cocoa classes are allocated on the heap, so they must be allocated/deallocated, and there's all the other overhead such as reference counting. They are also likely to end up spread out in memory, which means that there may be significant performance losses due to the memory blocks they reside in having to be paged in and out of cache.

Upvotes: 8

Jef
Jef

Reputation: 4728

If you've been playing with Objective-C for a while then you'll know that it is an OOP layer on top of coreFoundation, which is all structs and 'opaque types' (structs with secrets)..

For example, NSDictionary is really just a wrapper around the CFtype, CFDictionaryRef. Well, the things you're asking about here, size, point, rect, edgeInsets, etc. are just little data types which were determined to not warrant the upgrade. Primitives (int, double, bool, etc.) didn't get a (public) class to toll free bridge either. They got the NSNumber cluster, and these guys all got bunched together in the NSValue wrapper. You can write a concrete class to wrap a specific one if you need to...

Upvotes: 1

ReDetection
ReDetection

Reputation: 3196

Also a good point is operation speed. These points and rects are mostly used to render something and thus need faster operating than ever. Instead of allocating an object, which will trigger recursive init, spending a lot of bytes and cpu cycles for undercover work, it's just faster to say "here I have 16 bytes which is 2 CGFloats of NSPoint struct". This also makes a lot of sence when delegating work to a GPU, which don't know anything about OOP and methods of your objects, but need to draw a lot on screen without glitches.

Upvotes: 4

marvin_yorke
marvin_yorke

Reputation: 3559

Because they need to be value types. Point or rectangle are not objects actually. They are just a bunch of data. They do not behave, they just store data you pass into them. You can write

CGRect frame = ...
UIView *view1 = [[UIView alloc] initWithFrame:frame];

frame.origin = ...
UIView *view2 = [[UIView alloc] initWithFrame:frame];

And it works fine. With reference types, which classes are, you will alter the frame of view1 while moving frame to another origin.

[myRect intersectsWithRect: otherRect] definitely would be nice and actually Swift allows to do it. Value types like structs and enums can include methods in Swift, which makes it possible

Upvotes: 1

nalexn
nalexn

Reputation: 10791

Each programming paradigm has its own pros and cons, and object-oriented programming (OOP) in not an exception.

All major benefits from having classes (that is, writing in an object-oriented style) is encapsulation, polymorphism and inheritance.

If we declare such simple units as Rect or Point a class, we won't use anything from that list, but we'll bring all the disadvantages that OOP has, including implicit mutability, more complex memory management, pointer references, implicit actors, broken encapsulation (with setters/getters), etc. And I don't list here hundreds of anti-patterns that do exist in OOP.

I doubt that the choice of structs for Rect and Point in Cocoa was justified by C legacy, first of all because Objective-C supported classes from the outset, and secondly because the brand new Swift language does not have this legacy, but still almost all standard types and containers are declared in its standard library as structures, not classes.

In general, if you don't need encapsulation, polymorphism and inheritance - you should consider declaring your new entity as a struct and avoid OOP whenever possible.

Upvotes: 12

Omar Al-Shammary
Omar Al-Shammary

Reputation: 314

You use structs when you want to pass things by value and classes when you want to pass them by reference.

Upvotes: 0

Razvan
Razvan

Reputation: 4122

I believe it has to do with the fact that each struct holds primitive types of data (in general floats and doubles) without any actions on their own (like functions or methods) so there was no need for something more complex like a fully featured class (no imports and no boilerplate code eg. initializers) and of course, as other colleagues mentioned, because Objective-C is a superset of C.

Upvotes: 2

jamihash
jamihash

Reputation: 1900

Generally a class is used when there are methods that operate on the data. If you have data only then simply use a struct. It seems there are not any useful methods to going along with point or rect so no need for a class.

Upvotes: 2

Related Questions