0

I'm working on a legacy project, in which the original developers have chosen to represent monetary values with floats (I know...)

We've taken on the task of switching every variable and property in the project that handles monetary values to NSDecimalNumber as suggested in the answer to this question.

One small issue we've run into is that NSDecimalNumbers do not use the standard arithmetic operators, and instead use methods. That is, when you use arithmetic operators, you're adding the memory addresses, and not the actual values. Overloading the arithmetic operators does not seem to be possible in Objective-C, although it would be with C++.

I'm thinking it's possible to create a category method on NSDecimalNumber, written in C++. I understand it's possible to add and compile C++ files as part of an Xcode iOS project, although I haven't done this and am not familiar with C++.

In looking for examples of how something like this would be done, I'm not finding a very much. Can anyone tell me:

1) Is it possible to do what I'm describing above?

2) What would the syntax be for this?

raydowe
  • 1,285
  • 1
  • 16
  • 31
  • Sounds to me like what you really want to do is introduce a new typedef 'Currency' so that you can then change it as and when required without changing 400 different entries. (e.g. when you decide that NSDecimal Number isn't portable enough; or needs to store the currency symbol too) – UKMonkey Jan 11 '18 at 10:38
  • Why do you insist of writing your category in C++ if you've never done it and are not familiar with C++? – mag_zbc Jan 11 '18 at 10:53
  • @mag_zbc because, from my understanding, C++ supports overloading arithmetic operators where Objective-C does not. I will update to question to more clearly include that. – raydowe Jan 11 '18 at 11:03

1 Answers1

1

I believe you are on the right track but may be facing a few more issues. First of all as already mentioned in the comment by @UKMonkey you are probably looking to change it to some typedef which used to be float and then change that typedef as required.

There is no reason for your typedef to point to a NSDecimalNumber then. What you need for it is to correspond to some interface which in your case seems to be a few overloaded operators. That being said you should probably try creating a new C++ class that will wrap NSDecimalNumber and have its own overloaded operators.

This can be done using pretty standard C++ procedures but now the fun part begins... I am not sure how embedding an ARC supported object will work within a C++ structure; what you are putting it in is just a pointer and you have no way of telling it what it should do to when assigned. So it might be you would need to disable ARC for this specific class (can be done per file) and implement destructor which would release your decimal number.

The next problem I can think of is that if your class exposes C++ functionality it means that all the files that use/import this C++ class will need to support C++ which means they must be renamed to .mm (or use C++ flags on them).

Otherwise I believe you are pretty much in the clear of accomplishing this but I would ask some expert C++ developer for opinion on this class as to how best overload operators and how to properly handle assignment. For instance if you do MyValueType a = anotherMyValueTypeInstance; should internal decimal number be copied or reused as a pointer... Also if anything can be done to use constants like MyValueType a = 0; because otherwise you will need to use functions (C++ doesn't even support static methods if I remember correctly) so MyValueType a = MyValueTypeZero();.

As for adding operators directly on NSDecimalNumber in objective C it is not possible even in theory. The thing is that you are not using NSDecimalNumber but NSDecimalNumber * which means you would be overloading operators on pointers, not on the object itself. Your compiler tells you you can't do arithmetic operations on them by design. As far as C goes summing 2 pointers is completely valid or writing something like:

MyType *buffer = (MyType *)1000; // Not that it makes sense
for(MyType *ptr = buffer; ptr < 1100; ptr++) doSomething(ptr[0]);
Matic Oblak
  • 16,318
  • 3
  • 24
  • 43