4

What are the different ways of setting a NSDecimal to zero? I'm not keen on any of the 3 I found so far.

NSDecimal zero = {0}; // Not obvious what's going on here.

NSDecimal zero = @(0).decimalValue; // @(0) appears to always return the same instance.

NSDecimal zero = [NSDecimalNumber zero].decimalValue; // [NSDecimalNumber zero] appears to always return the same instance.

Is there one that is most accepted than others? Am I missing some kind of NSDecimalZero constant/function?

hpique
  • 119,096
  • 131
  • 338
  • 476
  • Are you sure about using `NSDecimal` instead of `NSDecimalNumber` ? – viral Apr 23 '13 at 09:37
  • @Viral Isn't NSDecimal slightly more efficient? See: http://stackoverflow.com/a/1710277/143378 – hpique Apr 23 '13 at 09:39
  • @hpique If effeciency really bothers you, I wouldn't use anything involving (possible) temporary objects and method calls to initialize the `NSDecimal` structure. Maybe a `#define NSDECIMALZEROINIT {0}` might help around the "not obvious what's going on here" issue. – Dirk Apr 23 '13 at 09:41
  • For Object oriented approach use `NSDecimalNumber`: http://stackoverflow.com/questions/1704504/what-is-the-right-choice-between-nsdecimal-nsdecimalnumber-cfnumber/1704851#1704851 – viral Apr 23 '13 at 09:45

3 Answers3

4

I have never noticed that NSDecimal doesn't have a nice Create function.

I can't imagine another method than the 3 you list.

NSDecimal zero = {0};

You are right, this is not obvious, this is actually very far from obvious. Usual programmers won't look up the documentation to see what value the struct will represent with all attributes set to zero.

NSDecimal zero = @(0).decimalValue

I don't like it because it uses NSNumber and needlessly creates an autoreleased object.

NSDecimal zero = [NSDecimalNumber zero].decimalValue

This is my preferred solution. Using NSDecimal structs directly is done mostly for performance boosts (without creating objects on the heap). This method matches the intent because it uses a singleton constant.

However, if you have a lot of code involving NSDecimal and performance is really important for you, create your own function/macro to initialize the struct and use this function everywhere. Then this problem won't matter to you because the function name will make the code obvious.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 1
    `@(0)` doesn't create an autoreleased object. It reuses the same instance for all `@(0)` calls. – hpique Apr 23 '13 at 09:54
  • @hpique You are wrong `Objects created using the literal or boxed expression syntax are not guaranteed to be uniqued by the runtime` ([Objective-C Literals](http://clang.llvm.org/docs/ObjectiveCLiterals.html)). However, I just noticed that `@(0)` is an expression literal but `@0` is a number literal. It would make more sense to use `@0`. – Sulthan Apr 23 '13 at 10:01
  • 1
    While I agree that it's not guaranteed, in practice @(0) or @0 appears to always return the same object. – hpique Apr 23 '13 at 10:03
  • @hpique True but not reliable. I think the best solution would be the one mentioned in LLVM docs - creating my own constant with any of the mentioned method and use it. – Sulthan Apr 23 '13 at 10:06
  • I just checked the docs for `[NSDecimalNumber zero]`. It doesn't say anywhere that it is guaranteed to return a singleton object. – JeremyP Apr 23 '13 at 14:56
  • @JeremyP True, I just supposed, my bad. Then custom constants are the only way to go. – Sulthan Apr 23 '13 at 15:00
  • @Sulthan I wasn't meaning to suggest your method is wrong, only that it doesn't necessarily return a singleton. I bet in practice, it does, but that is irrelevant to the functionality of the method. – JeremyP Apr 23 '13 at 15:11
2

NSDecimal is a C struct which you are not supposed to look inside (you can but you shouldn't) so that rules out the first which is technically looking inside the struct.

Either of the second two are absolutely fine. Note that, in C, assigning to a struct copies all the fields, so although [NSDecimalNumber zero] always returns the same object, your NSDecimal will be a unique struct and changing its contents won't affect any other NSDecimal that has been "created" in the same way.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • That's exactly my problem with the first option. And NSDecimal has underscored members, which makes it even more scary. What I find odd is that I need to use an object to properly initialise an enum. I expected a way to do this with the related enum functions. – hpique Apr 23 '13 at 09:49
  • @hpique It's not an enum, it's a struct and these are fairly common in Cocoa e.g. NSRange, NSRect. I do find it a little bit jarring to suddenly come across in an environment where almost everything is an Objective-C object, but that's the way it is. – JeremyP Apr 23 '13 at 14:53
  • 1
    Struct is what I meant. :P My mistake aside, what I find odd is that there's doesn't seem to be a way to initialise NSDecimal to zero using the functions provided with the struct. Or as @Sulthan put it, "NSDecimal doesn't have a nice Create function". – hpique Apr 23 '13 at 16:16
0

I guess you need to use NSDecimalNumber,

Typically we do as:

NSDecimalNumber *zeroDecimal = [[NSDecimalNumber alloc] initWithFloat:0.f];

NSDecimal zero = @(0).decimalValue; // @(0) appears to always return the same instance.

NSDecimal zero = [NSDecimalNumber zero].decimalValue; // [NSDecimalNumber zero] appears to always return the same instance.

Above two returns equivalent value of 0.0, first one is just the shorthand notation for the second one. You boxed 0 to NSDecimalNumber, using new syntax.


However, NSDecimal is typedefStruct that looks like this

typedef struct {
    signed   int _exponent:8;
    unsigned int _length:4;     // length == 0 && isNegative -> NaN
    unsigned int _isNegative:1;
    unsigned int _isCompact:1;
    unsigned int _reserved:18;
    unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;
Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140