17

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?

Community
  • 1
  • 1
Oliver Cooper
  • 849
  • 7
  • 20
  • 2
    Performance? Dynamic dispatch is great except for lots of calls methods with very small bodies. – Jasper Blues Apr 06 '15 at 08:24
  • Do you mean CGRect and CGPoint? It's worth noting that the CoreGraphics library predates the use of ObjC (NextStep) so wouldn't have been able to be objects when written. – OrangeDog Apr 06 '15 at 13:19

9 Answers9

12

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nalexn
  • 10,615
  • 6
  • 44
  • 48
  • I'm not sure this really addresses the question. The Foundation framework does offer functions for working with structs like `NSRect` and `NSPoint` (as well as `NSSize`, `NSRange`, etc.) that could easily be justifiable as methods. And if Objective-C classes can be said to have "broken encapsulation", then encapsulation in C structs is _really_ broken. You can't really compare to Swift's structs, either, as Swift's structs are closer to Objective-C classes than they are to C structs. – mipadi Apr 06 '15 at 19:04
  • In C and Obj-C structs don’t have encapsulation at all, so it’s not broken, as I said, if you need this in Obj-C you should probably use classes. Structs have other strong sides. With regards to the structs in Swift, the fact that you can declare methods that are “namespaced” to a struct does not imply that structs now can BEHAVE like objects - they still are very different. – nalexn Apr 06 '15 at 19:29
  • In what way do Swift's structs have any similarities to C's structs? – mipadi Apr 06 '15 at 19:31
  • Structs are value types in both these languages - this is probably the main similarity. Classes are reference types, as you know. I don't argue that structs in Swift can do much more than structs in C. You have been given with tons of syntax sugar (which I also enjoy), but still, the semantics of struct didn't change. – nalexn Apr 06 '15 at 19:39
  • For everyone who have read down to this comment I would recommend watching videos from [this conference](http://2014.funswiftconf.com/). Very inspiring to use structs. – nalexn Apr 06 '15 at 19:48
  • The semantics changed quite a bit. Swift structs can have methods, for example, while C structs can't, a point that is germane to this discussion. The only notable difference between Swift structs and Objective-C classes are the value/reference distinction; otherwise, Swift structs are very much like Objective-C classes. – mipadi Apr 06 '15 at 20:21
  • Although I feel you haven't entirely answered the point regarding having value method names I feel you've given the best reasoning. Although most answers raise good points. While it would naturally be better to have someone from Apple enlighten us, I've marked your answer as correct. – Oliver Cooper Apr 08 '15 at 02:01
8

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.

Nick Lockwood
  • 40,865
  • 11
  • 112
  • 103
4

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.

ReDetection
  • 3,146
  • 2
  • 23
  • 40
  • Performance is almost definitely the answer. These design decisions date back to the NeXT days, when computers were much less powerful and performance -- especially in key low-level drawing code -- was critical. Of course, it's hard to say without talking to the people who actually wrote the frameworks. – mipadi Apr 06 '15 at 20:39
3

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.

Paolo
  • 15,233
  • 27
  • 70
  • 91
  • 1
    This doesn't really address why some data types, such as `NSRect` are structs and others are Objective-C classes. – mipadi Apr 06 '15 at 18:59
  • @mipadi I agree. I misunderstood the OP's question. (I thought he was talking about C++ classes) – Paolo Apr 07 '15 at 14:53
2

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.

jamihash
  • 1,900
  • 1
  • 12
  • 15
  • 2
    What about functions like 'NSIntersectsRect', 'NSPointFromString' and even 'NSMakeRect'? Wouldn't it make more sense to do [myRect intersectsWithRect: otherRect]? – Oliver Cooper Apr 06 '15 at 07:34
  • 1
    I agree. Perhaps there are legacy code reasons - I am guessing. – jamihash Apr 06 '15 at 07:41
2

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.

Razvan
  • 4,122
  • 2
  • 26
  • 44
  • There are several functions that operate on both `NSPoint` and `NSRect` though which would have made sense as methods, so I'm not sure this is the reason. – mipadi Apr 06 '15 at 18:54
1

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...

Jef
  • 4,728
  • 2
  • 25
  • 33
1

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

marvin_yorke
  • 3,469
  • 4
  • 25
  • 35
  • That is a good point, although it wouldn't be overly complicated to solve. – Oliver Cooper Apr 06 '15 at 14:27
  • 2
    Sure, but it's about difference between a value-type and an object. Object encapsulates data (i.e. there could be hidden data inside of an object that is not visible to the outer world), struct just stores it. Objects can behave (i.e. alter their own properties with time), while value types cannot. http://realm.io/news/andy-matuschak-controlling-complexity/ check out this talk. Binding functions to data itself is nice, but you don't necessarily need a `class` to achieve it – marvin_yorke Apr 06 '15 at 15:19
0

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

Omar Al-Shammary
  • 304
  • 3
  • 13