2

I have a NSDecimalNumber and an NSInteger. I want to multiply the former by the latter, so I'll have to convert the integer. This is what I came up with, after some trial and error.

NSDecimalNumber *factor = (NSDecimalNumber*) [NSDecimalNumber numberWithInteger:myInteger];

It feels like I'm really driving the point home:

  1. Hi there, I want an NSDecimalNumber, let's call it factor.
  2. By the way, just so you know, I want that to be an NSDecimalNumber, if that'd be possible.
  3. So could you give me an NSDecimalNumber? Here, I'll give you an integer to use as a source.

Is it supposed to be this verbose? Or am I messing up somewhere?

Andrejovich
  • 544
  • 2
  • 13

2 Answers2

5

The (NSDecimalNumber*) type-cast is "necessary" because +numberWithInteger: is an NSNumber method that returns an NSNumber object. However, this is actually going to cause problems, because it's returning an NSNumber object, not an NSDecimalNumber. (How to use NSDecimalNumber?)

To get your integer into a decimal number, simply do this:

NSDecimalNumber *factor = [NSDecimalNumber decimalNumberWithDecimal: [@(myInteger) decimalValue]];

It's still fairly verbose but two things to bear in mind:

  • Objective-C is very verbose, by design.
  • NSDecimalNumber in not intended for basic integer arithmetic, it's intended for use with numbers that are typically represented using scientific notation.
Community
  • 1
  • 1
Patrick Perini
  • 22,555
  • 12
  • 59
  • 88
1

The API you call is a NSNumber convenience constructor which returns an NSNumber -- not necessarily an NSDecimalNumber. A convenience constructor does not need to return a type of the class you message, but an instance of the declared return type. Because NSDecimalNumber is a subclass of NSNumber, an explicit downcast is required when assigning an NSNumber to an NSDecimalNumber.

If a library writer intended to specify the expectation you have in mind (to return an instance of the class you have messaged), instancetype would be used for the return type. Unfortunately, it is a rather new keyword and does not exist in all places it possibly could exist. If instancetype had been used, the cast would not be necessary.

Before instancetype existed, a simple id was the convention. With id, no cast is required and no type checking performed when assigning/initializing a variable of an Objective-C type. For example: NSArray * array = [NSString string]; would not be flagged by the compiler if the return type were id, but it would be flagged if the return type were instancetype. NSMutableString * string = [NSMutableString string]; would be flagged by neither, but it would be flagged if +string's return type were declared + (NSString *)string;.

justin
  • 104,054
  • 14
  • 179
  • 226