Trying to create NSDecimal in iPhone-Wax
Asked Answered
B

2

6

Here is a problem I am facing:

I create an NSDecimalNumber in Wax with the line

    local x=NSDecimalNumber:initWithString("2.3") 

Out of this I would like to create a NSDecimal with the following line

   local y=x:decimalValue() 

This promptly crashes the program.

To create the same experience you need to create a basic wax project and add the two lines as the lat lines of function applicationDidFinishLaunching in AppDelegate.lua.

Question: How can I get this to return an honest NSDecimal which I can pass along? I don't actually need to see or print the number myself.


Appendicies

  1. Despite popular belief on the internet, NSDecimal is very different from NSDecimalNumber. The first is a C struct, the second is an Obj-C struct with which I work very well.
  2. To get NSDecimalNumber to work I need to comment out lines 222-224 (NSNumber) and 241-246 (NSValue) from wax-helpers.m.
  3. NSDecimal is defined in Foundation/NSNumber.h

Output when run: There's not much of a stack trace, it just silently dies. In the Debugger (with breakpoints turned on) there is the following (abbreviated) calling sequence:

#0  0x027553f4 in objc_exception_throw
#1  0x0256e8d6 in __NSGetSizeAndAlignment
#2  0x0256ebd9 in __NSGetSizeAndAlignment
#3  0x025747b8 in __NSMS1
#4  0x02573f9c in +[NSMethodSignature signatureWithObjCTypes:]
#5  0x000342d0 in wax_selectorForInstance at wax_helpers.m:557
#6  0x00035bc2 in __index at wax_instance.m:303
#7  0x000181b9 in luaD_precall at ldo.c:319
#8  0x00018405 in luaD_call at ldo.c:376
#9  0x0002c488 in callTMres at lvm.c:88
#10 0x0002c74a in luaV_gettable at lvm.c:125
#11 0x0002dd26 in luaV_execute at lvm.c:467
#12 0x0001841c in luaD_call at ldo.c:377
#13 0x0000ddc8 in f_call at lapi.c:800
#14 0x0001758a in luaD_rawrunprotected at ldo.c:116
#15 0x0001879a in luaD_pcall at ldo.c:463
#16 0x0000de65 in lua_pcall at lapi.c:821
#17 0x00034e60 in wax_pcall at wax_helpers.m:826  
#18 0x00036be4 in pcallUserdata at wax_instance.m:580
#19 0x00036edc in wax_id_call at wax_instance.m:627

Sometimes there is the following tiny stack trace:

wTest[36403:207] PANIC: 

Error
-----
Error calling 'applicationDidFinishLaunching:' on lua object '<AppDelegate: 0x6300e50>'
data/scripts/AppDelegate.lua:39: attempt to index local 'x' (a number value)
stack traceback:
    [C]: ?
data/scripts/AppDelegate.lua:39: in function <data/scripts/AppDelegate.lua:19>

This matches what the debugger gives: Wax is trying to call a method for a number value.

Balmung answered 20/6, 2011 at 1:26 Comment(3)
Define "crashes the program". Do you have a backtrace? Moreover, the edits to the wax helpers seem…brutal. It looks like you'll prevent Objective C wrapped numbers and structures from becoming Lua numeric types at all (they'll all be opaque objects to the Lua code). This may be the root of the problem.Hebel
By crash It means the program throws an exception and stops. I'll add the stacktrace later today. Its main complaint is that I'm trying to apply a method to a number (something to that effect, this is from memory). I commented out those lines precisely to prent wax from unwrapping the numeric objects because that's part of the problem. If you have a better way to do it I'm all ears.Balmung
Okey doke - when you've a stack trace, I should be able to diagnose it. The gist of what you said is what I suspected (that somewhere inside Wax, it's still getting translated to a Lua primitive number, rather than staying as an object).Hebel
H
2

Important Edit: OK, I'm stupid (and looking for complex answers to simple questions). A quick read of the Wax blog and I find https://github.com/probablycorey/wax/wiki/Overview, which mentions the toobjc function. As such, it looks a like like...

local x = (toobjc)(NDecimalNumber:initWithString("2.3"));

will do what you want (i.e. prevent automatic Lua type conversion). I may have the syntax slightly wrong, so experiment. I've left my original answer below to illustrate another "solution".


So, looking over Wax (which I'm not intimately familiar with), one key act it performs when bridging Objective C and Lua is to convert all Objective C types it can into suitable native Lua types. This includes NSNumber types (such as NSDecimal) which are mapped to Lua number types.

Of course, you already know this, hence your changes to wax-helpers.m. Alas, what you've done isn't quite enough - conversions are still happening, and hence your NSDecimalNumber still becomes a number. It seems that, depending on whether this gets used in your Lua code, either Lua blows up (trying to index a scalar type), or the Objective C bridge blows up. I'm not sure why you only get the Lua trace error sometimes (assuming your code is always identical); it points to some underlying assumptions about the internal Wax state being violated.

The best solution will be one that doesn't involve changing Wax. At the moment, even if the "fix" did work, you've totally disabled the automated coercion between types. This will, I assume, break quite a lot of Wax code and idioms. Looking at Wax, it will only perform automated conversions for types that subclass certain Foundation classes it specifically understands; any object type that it doesn't know about remains an object. In this case, we're caught in the NSValue and NSNumber conversion, so my first suggestion is to simply wrap NSDecimalNumber in some class that Wax doesn't understand. Something like...

@interface MyDecimalWrapper : NSObject
{
  NSDecimalValue *myDecimal;
}

- (NSDecimalValue*)getDecimalValue;
- (NSDecimal*)getDecimal;

@end

@implementation MyDecimalWrapper

- (NSDecimalValue*)getDecimalValue { return [[myDecimal retain] autorelease] }
- (NSDecimal*)getDecimal { return [myDecimal decimalValue]; }

@end

This can be added to Wax without changing it's code significantly, and using this to carry a NSDecimalValue across the bridge should prevent Wax's type conversion. Of course, if you use getDecimalValue inside Lua, the result will promptly be wrapped into a Lua number. If you need to call methods on the underlying NSDecimalValue in Lua, just proxy them from equivalent methods defined on the wrapper.

If this absolutely doesn't work for you, I can probably work out the changes needed to Wax. But it will be a world of hurt maintaining your own port, and breaking lots of existing Wax code and examples.

Tangentially: I'm not sure what you intend to do with an NSDecimal once you've got one in Lua. It's an opaque C structure, that can only be used through a C interface provided by Foundation.

Hebel answered 24/6, 2011 at 19:54 Comment(4)
The toobjc trick fails because the object printed is "(0x60489e4 => 0x6048900) 2.3". This is exactly the same as commenting out the wax-helper lines. The output I expected is something like "(0x60489e4 => 0x6048900) <ObjectName: ox6048900>"Balmung
The idea of a wrapper object fails too for the same reason. It looks like the conversion is happening deeper than I expected.Balmung
Related question: https://mcmap.net/q/1917301/-integrate-core-plot-and-waxBalmung
One more question: #6482373Balmung
R
0

Maybe you should try NSScanner to create NSDecimal from string.

Ragtime answered 24/6, 2011 at 9:19 Comment(2)
The problem with NSScanner is that it wants the address to NSDecimal. I do not know how to do it in wax. Perhaps you can show me?Balmung
Nevermind, wax cannot convert pointer to NSDecimal returned from scanDecimal to userdata saying "Converstion from ^{?} to Objective-c not implemented."Ragtime

© 2022 - 2024 — McMap. All rights reserved.