{\rtf1\mac\deff2 {\fonttbl{\f0\fswiss Chicago;}{\f2\froman New York;}{\f3\fswiss Geneva;}{\f4\fmodern Monaco;}{\f13\fnil Zapf Dingbats;}{\f14\fnil Bookman;}{\f15\fnil N Helvetica Narrow;}{\f16\fnil Palatino;}{\f18\fnil Zapf Chancery;}{\f20\froman Times;} {\f21\fswiss Helvetica;}{\f22\fmodern Courier;}{\f23\ftech Symbol;}{\f33\fnil Avant Garde;}{\f34\fnil New Century Schlbk;}{\f55\fnil Code 3 of 9;}{\f1904\fnil AppleIcon;}{\f2029\fnil Nadianne;}{\f2052\fnil Zeal;}{\f12899\fnil AppleGaramond LtIt;} {\f12900\fnil AppleGaramond BkIt;}{\f12901\fnil AppleGaramond BdIt;}{\f12902\fnil AppleGaramond Lt;}{\f12903\fnil AppleGaramond Bk;}{\f12904\fnil AppleGaramond Bd;}}{\colortbl\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blu e255; \red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\ green255\blue0;\red255\green255\blue255;}{\stylesheet{\s243\qj\fi180\sa24 0\keep\tqc\tx4320\tqr\tx8640 \f20 \sbasedon0\snext243 footer;}{\s254\qj\sb120\sa240\keep \b\f20 \sbasedon0\snext0 heading 2;}{\s255\qj\sb240\sa240\keep \f20\fs36 \sbasedon0\snext0 heading 1;}{\qj\fi180\sa240\keep \f20 \sbasedon222\snext0 Normal;}{\s2\li360\sa240\keep \f20 \sbasedon0\snext0 BulletList;}{\s3\sa240\keep \f22 \sbasedon0\snext0 code;}{ \s4\qc\fi180\sa240\keep \f20\fs48 \sbasedon0\snext4 Title;}{\s5\qc\fi180\sa240\keep \f20\fs28 \sbasedon0\snext5 Byline;}{\s6\qc\fi180\sa240\keep \f20 \sbasedon0\snext0 Caption;}{\s7\qj\sb240\sa240\keep \f22\fs36 \sbasedon255\snext7 CodeRef;}} \margl720\margr720\margt1080\margb720\deftab360\widowctrl\ftnbj \sectd \sbknone\linemod0\linex0\cols1\endnhere {\footer \pard\plain \s243\qr\fi180\sa240\keep\tqc\tx4320\tqr\tx8640 \f20 "Newton still needs the card you removed." \endash \chpgn \par }\pard\plain \s4\qc\fi180\sa240\keep \f20\fs48 "Newton still needs the card you removed."\par \pard\plain \qc\fi180\sa240\keep \f20 {\fs36 DRAFT 5\par }\pard\plain \s5\qr\fi180\sa240\keep \f20\fs28 Michael S. Engber\line Apple Computer - PIE Developer Technical Support\line Copyright \'a9 1993 - Michael S. Engber\par \pard\plain \qj\fi180\sa240\keep \f20 This article was (will be) published in the February 1994 issue of Double-Tap magazine. For information about Double-Tap , contact the Software Frameworks Association at FRAMEWORKS@APPLELINK.APPLE.COM or (408)253-2765 .\par \pard\plain \s6\qc\fi180\sa240\keep \f20 {{\pict\macpict\picw176\pich76 04ef00000001004c00b11101a00082a03039a0008e01000a0000000003080240980018000 00000004c00b800000001004c00b100000001004c00b1000107007fecff01800007007fec ff018000080060ed0002018000080060ed0002018000080060ed0002018000080060ed000 2018000080060ed0002018000080060ed00 02018000080060ed0002018000080060ed0002018000080060ed000201800018046002200 020fe0002820820fe0002200022fd000201800018046003200020fe0002800820fe000220 0022fd000201800019116002a72a71cb0079c208200b1c71e78073c7fe000201800019176 00268aa222c80808208200ca28a28002228 800000018000191760022faa2228807082082008befa2700222f800000018000191160022 82a2228800882082008a08220802228fe000201800019176002279419c880f0620820089e 79ef001a27800000018000080060ed0002018000080060ed0002018000080060ed0002018 000080060ed0002018000130060fe000008 f9000308003c20fd0002018000130060fe000008f9000308002220fd00020180001917600 1c7ac78089c880b1cf1c89c78002221c79e70000180001917600228b28808a2880ca2aa28 a288003c2228a088000180001917600208a08808a288083eaa28be88002023e89cf800018 0001917600209a08808a2980820aa252088 0020220982800001800019176001e6a078079c68081ea9c21e78802021e6bc78000180000 c0060fc000080f300020180000c0060fd000007f20002018000080060ed00020180000800 60ed00020180001608600080000002002080fc0002020018fd0002018000130060fd00030 2000080fa000020fd000201800019116000 8b1e72c70021c02c72a01cb0022c71cbfe0002018000191760008ca08b22002080328aa02 2c80232222cbe000001800019116000889cfa02002080228aa0228002222228fe00020180 001911600088828202002080228aa0228002222228fe00020180001911600088bc7a01802 0602271401c80022221c8fe000201800008 0060ed0002018000080060ed0002018000080060ed0002018000080060ed0002018000170 46000000820fd00010880fd000080fe00048000018000160360000008fc00010880fd0000 80fe0004800001800019176003c79c21cb0072c01cf1c01c7ac780f1e880f1c0018000191 76002a888222c808b20088a20228b2880aa 28808a2001800019176002a8882228808a20088be0208a0880aa28808be00180001917600 2a9882228808a20088a00209a0880aa68808a0001800019176002a68621c88072200689e0 1e6a0780a9a780f1e00180000b0060f000058000000180000c0060f1000007fe000201800 0080060ed0002018000080060ed00020180 000e02600020fe000002f300020180000e02600020fe000002f300020180000e066001e7b c79e71ef300020180000e06600228aa8a28a2f300020180000e06600228aa8a2fa2f30002 0180000e06600229aa9a2822f300020180000f076001e6aa69e79e20f400020180000c006 0fd000020f200020180000d0060fe000101 c0f20002018000080060ed0002018000080060ed0002018000080060ed000201800008006 0ed0002018000080060ed0002018000080060ed0002018000080060ed0002018000080060 ed0002018000080060ed0002018000080060ed000201800007007fecff01800007007fecf f018000a0008fa00083ff}}\par \pard \s6\qc\fi180\sa240\keep Figure 1 \endash Card Reinsertion Message (you blew it)\par \pard\plain \qc\fi180\sa240\keep \f20 {{\pict\macpict\picw208\pich115 066c00000007007300d71101a00082a03039a0008e01000a000000000308024098001c000 00000007300d800000007007300d700000007007300d700011d1b000fffff0003f000fc00 3f000fc003f000fc003f000fe001ffffe0001d1b003fffffe01ffe07ff81ffe07ff81ffe0 7ff81ffe07ffc0ffffff8000801007fe9ff 01fc000801007fe9ff01fc00070000e8ff01fe00070000e8ff01fe00070000e8ff01fe001 d1b00ff0000fffc0fff03ffc0fff03ffc0fff03ffc0fff01ffe0000fe001d1b00fe00001f e001f8007e001f8007e001f8007e001f8003f000007e00080100fee900017e00080100fee 900017e00080100fee900017e00080100fe e900017e00080100fee900017e00080100fee900017e000a0300fe001eeb00017e000b040 0fe007f80ec00017e000c0500fe00e1c210ed00017e000f0800fe00ccc3100000c0f00001 7e00100900fe01806393cccde79bf100017e00110a00fe019c63d66cccccdd80f200017e0 0110a00fe018c62f7e6d8ccd980f200017e 00110a00fe018c627607f8ccd980f200017e00110a00fe00dec2360330ccd980f20001fe0 0110a007e00e1c213e330679980f20001fe000b04007f007f80ec0001fe000b03007f001e ec000201fc000a02003f80eb000203f8000a02003f80eb000203f8000a02003f80eb00020 3f8000a02003f80eb000203f8000a02003f 80eb000203f8001703003f80f0fb000361800018fb00010180fe000203f8001703007f018 0fb000361800018fb00010180fe000201fc001d15007f01c39ad6c070f34e799cee1e38e1 c73b6d69c780fe000201fc001d15007f00e6def6c018dbdb6db6db1b0d836c636f7b6d80f e000201fc001c1500fe0076d8c6c078db1b 6dbedb1b3de36c636c63ed80fd0001fe001c1500fe0036d8c380d8db1b6db0db1b6c636c6 36c630d80fd0001fe001c1500fe01e398c19878f30e799edb1b3dc1c739ec61e7b0fd0001 fe000f0100fefe0003030800c0f00001fe000f0100fefe0003061000c0f00001fe0008010 0fee90001fe00080100ffe90001fe000901 007fea000201fc000f03007f0060fd000018f1000201fc001008007f80c030f063c30cf10 00201fc001008003f80807198e66704f1000203f8001008003f81803199666306f1000203 f8001008003f818e319a666306f1000203f8001008003f8180319bf66306f1000203f8001 008003f80803198666304f1000203f80011 09007f80c030f063c30cc0f2000203f8000f03007f0060fd000018f1000201fc000901007 fea000201fc00090100ffea000201fc00080100fee90001fe00080100fee90001fe000801 00fee90001fe00080100fee90001fe00080100fee90001fe00080100ffe90001fe0009010 07fea000201fc000901007fea000201fc00 0a02007f80eb000201fc000a02003f80eb000203f8000a02003f80eb000203f8000a02003 f80eb000203f8000a02003f80eb000203f8000a02003f80eb000203f8000a02007f80eb00 0203f8000901007fea000201fc000901007fea000201fc00090100ffea000201fc0008010 0fee90001fe00080100fee90001fe000801 00fee90001fe00080100fee90001fe00080100fee90001fe00080100fee90001fe0009010 07fea000201fc000901007fea000201fc000901007fea000201fc000a02003f80eb000203 f8000a02003f80eb000203f8000a02003f80eb000203f8000a02003f80eb000203f8000a0 2003f80eb000203f8000a02003f80eb0002 03f8000901007fea000201fc000901007fea000201fc000901007fea000201fc000a0100f eeb0003ffe0fe000b0100feec000401fff0fe000b0100feec0004018030fe000b0100feec 000401b1b0fe000b0100feec000401bbb0fe000b0100feec0004019f30fe000b0101feec0 004018e30fe000b0101feec0004019f30fe 000b0100feec000401bbb0fe000b0100feec000401b1b0fe000b0100feec0004018030fe0 00b0100feec000401fff0fe000a0100feeb0003ffe0fe00080100fee90001fe00080100fe e90001fe001d1b00fe00001fe001f8007e001f8007e001f8007e001f8003f00000fe001d1 b00ff0000fffc0fff03ffc0fff03ffc0fff 03ffc0fff01ffe0001fe00070000e8ff01fe00070000e8ff01fe00070000e8ff01fe00080 1007fe9ff01fc000801007fe9ff01fc001d1b003fffffe01ffe07ff81ffe07ff81ffe07ff 81ffe07ffc0ffffff8001d1b000fffff0003f000fc003f000fc003f000fc003f000fe001f fffe000a0008fa00083ff}}\par \pard\plain \s6\qc\fi180\sa240\keep \f20 Figure 2 \endash -10401 error (you blew it)\par \pard\plain \qj\fi180\sa240\keep \f20 This article will explain how to avoid programming errors that result in the messages shown Figures 1 and 2. Well- written Newton applications should be able to reside on a PCMCIA card and not trigger the reinsertion message or -10401 error when the card is removed. All you have to do is make sure you don't leave any references to your card around after it has been rem oved.\par \pard \qj\fi180\sa240\keep This sounds simple enough, but first you need to understand fully why the reinsertion message occurs, when it occurs, and what techniques are available to avoid it. This, in turn, requires an understanding of a variety of other topics. While I may seem to take a long time to get to the point, be advised this is an area where "a little bit of knowledge can be dangerous." I suggest taking the time to read and digest the whole article rather than just sprinkling calls to EnsureInternal throughout your code. I assume the reader is familiar with NewtonScript, has experience using NTK to write Newton applications, and has some idea about what InstallScripts and RemoveScripts are.\par \pard \qj\fi180\sa240\keep An additional disclaimer: Some of the details discussed in this article may change in future Newton products or with future versions of NTK. I've tried to point these out whenever possible.\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 Where Objects Reside \endash NewtonScript Heap Vs Packages\par \pard\plain \qj\fi180\sa240\keep \f20 NewtonScript data types can be divided into two categories; immediates and references. Immediate types are integers, booleans, and characters. Immediate data is stored completely in 32 bits, not as a pointer to the actual data. Everything else is a reference. That is, a pointer to the actual data. If you want to check out a particular object, use {\f22 PrimClassOf(foo)} ={\f22 }{\f22 'Immediate}.\par \pard \qj\fi180\sa240\keep Non-immediate NewtonScript objects reside in one of two places: the NewtonScript heap or a package. The NewtonScript heap is NewtonScript's working memory. When your program allocates an object dynamically (e.g., {\f22 foo := [x, y, z]}), the object resides in the NewtonScript heap.\par \pard \qj\fi180\sa240\keep The other place objects can reside is in packages. For example, if a string literal appears in your code, that string resides in your package. That string is a read- only object and you will get an error if you try to change a character in it (e.g. {\f22 s[0] := $Z}) or change its length (e.g. {\f22 SetLength(s,4)}). A good analogy is string literals in ANSI C. In C, you need to treat string literals as read- only because the compiler reserves the right to place them in protected memory or have different literals share the same memory. In many C implementations you can often get away with being sloppy, but on Newton your package is always in protected memory. \par \pard \qj\fi180\sa240\keep Here is a list of some common ways you can get references to objects in your package in your NewtonScript code:\par \pard\plain \s2\li360\sa240\keep \f20 \bullet string literals \endash {\f22 "abc"}\line \bullet real literals \endash {\f22 3.14}\line \bullet quoted symbols \endash {\f22 'foo}\line \bullet quoted arrays - {\f22 '[1,2,3]}\line \bullet quoted frames \endash {\f22 '\{slot1: 42, slot2: nil\}}\par \pard\plain \qj\fi180\sa240\keep \f20 Note that [\'c9] or \{\'c9\} appearing in your code without the quote means that a new array or frame will be created in the NewtonScript heap when the code executes. However, it's still possible for the resulting structure to have references to your package. Consider the following code:\par \pard\plain \s3\li180\sa240\keep \f22 \{slot1: "abc", slot2: '[1,2,3]\}\par \pard\plain \qj\fi180\sa240\keep \f20 A new frame is allocated in the NewtonScript heap, but its slots contain references to objects in the package. The problem can be even more subtle. Consider the following code:\par \pard\plain \s3\li180\sa240\keep \f22 \{slot1: nil, slot2: 42\}\par \pard\plain \qj\fi180\sa240\keep \f20 Even though the slots don't contain references to the package, the symbols used for the slot names reside in the package. This is a subtle point that I will address several times in this article.\par \pard \qj\fi180\sa240\keep I should also point out that all the template and proto layouts you create using NTK reside in your package. These are actually frames that are created at build-time. Since they are created at build-time , their slot initializers are evaluated at build-time. This leads to another way you can run into package references: slot initializers. For example, if you use {\f22 [}{\f22 1,2,3]} to initialize some slot in a template, that slot's initial value will be an array that resides in your package. It doesn't matter if you quote the array or not. It doesn't even matter if you use {\f22 Clone([1,2,3])} instead. The array will reside in your package. Remember, the slot's initial value is computed at build-time.\par \pard \qj\fi180\sa240\keep A related point is that objects you create in your "Project Data" file are also created at build-time. For example, when you create a build-time global in "Project Data" using {\f22 gFoo := \{a: 1, b: 2\}} and then use {\f22 gFoo} to initialize some slot, you end up with a reference to your package. Things work the same way for BeforeScripts and AfterScripts. Only code that runs after your package is downloaded to the Newton can create objects in the NewtonScript heap.\par You may already be familiar with the distinction between objects in the NewtonScript heap and objects in packages from experiences with error -48214, "object is read-only." Objects in packages are read-only. You must use copies in the NewtonScript heap if you need to modify them. This is when most people discover the functions Clone and DeepClone. These functions are sufficient to solve the read-only object problem, but they are not always sufficient to solve the invalid reference problem. \par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 Invalid References\par \pard\plain \qj\fi180\sa240\keep \f20 The Newton uses PCMCIA cards more like an extended RAM space than like an external file system. This combined with the fact that the user can remove a PCMCIA card at any time, causes an interesting problem. To draw an analogy to traditional programming, when the user removes a PCMCIA card it's more like yanking out some of a running computer's RAM than like removing a floppy disk.\par This means it is possible to have a valid reference suddenly become a reference to memory that is no longer available \endash that is, a reference to an object on the PCMCIA card the user is now holding in their hand. I will use the term " invalid reference," to describe such references. Drawing on your own programming experience, you might think of these as dangling pointers (pointers to objects that have since been deallocated or moved), but they are actually worse. Invalid reference s refer to memory that no longer even exist.\par There is another way users can make your package unavailable besides removing the card it's on. They can use Remove Software \endash via Prefs for internally stored packages or Card for packages on cards. The issues just discussed still apply. However, in this case you really do create dangling pointers as opposed to references to non-existent memory. For simplicity, this article discusses the problem in terms of card removal, but keep in mind the issue is package removal in general, not just card removal.\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 Using an Invalid Reference\par \pard\plain \qj\fi180\sa240\keep \f20 Newton handles attempts to use an invalid reference in one of two ways. If the invalid reference is to a card that's in the process of being removed, Newton puts up the reinsertion message, freezes (probably in the middle of executing your RemoveScript) and waits until the user reinserts the card so it can continue where it left off. If the invalid reference is encountered after the card removal process completes, the Newton throws a -10401 exception and aborts the code that was executing.\par When users get the reinsertion message, they really have only two choices: reinsert the card or reboot. Reinserting the card is safest because it lets the code finish executing. This doesn't necessarily mean they will subsequently may be able to remove the card without incident. The most troublesome applications continue causing the reinsertion message and the user must either remove the application from the card (with Remove Software) or reboot the Newton.\par In the -10401 case, users have no choice but to dismiss the error dialog. At this point they may be able to continue using Newton or it's possible that the invalid reference remains and will continue to cause errors until the Newton is rebooted.\par In either case, rebooting will get rid of any invalid references. Recall that these references exist in the NewtonScript heap and, when you reboot, the NewtonScript heap is reinitialized. This is not to say rebooting is a panacea. Rebooting from the reinsertion dialog means aborting some code that was executing \endash probably your RemoveScript. Similarly, the -10401 error means some code was aborted (by an unhandled exception). In practice, usually this isn't a problem, but, if the aborted code was part way through some operations involving soups, it i s possible things could be left in an inconsistent state.\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 PCMCIA Card Removal\par \pard\plain \qj\fi180\sa240\keep \f20 The Newton is designed so that as soon as the user unlocks a card it's no longer available. It doesn't matter when they physically eject the card. From your program's point of view it's gone a s soon as the unlock switch is thrown. This might be a useful fact to note when you're stress testing your application for handling card ejection. You can save time and reduce wear on the eject button and PCMCIA connectors by simply unlocking and locking the card.\par Your program doesn't get a chance to do something before the card goes away, but you do get a chance to do something immediately afterward, in your RemoveScript. That is often where programs get into trouble, usually because the RemoveScript tries to access an object residing on the card.\par This access might be as blatant as dereferencing a slot in your base view's template or as seemingly innocuous as trying to use RemoveSlot to clean up a printing format you tucked away in the root view. There are a wide variety of ways to access your card inadvertently. These errors and how to avoid them are discussed in a later section.\par The sequence of calls when a user removes a card, hopefully, will consist of the user unlocking the card followed by your RemoveScript executing \endash end of story. However, if your RemoveScript uses an invalid reference the sequence will be:\par \pard\plain \s2\li360\sa240\keep \f20 \bullet app is closed - ViewHideScript and ViewQuitScript called\line \bullet sometime later the user unlocks the card\line \bullet RemoveScript called\line \bullet invalid reference encountered \endash RemoveScript suspended\line \bullet user reinserts card\line \bullet RemoveScript continues\line \bullet InstallScript runs (due to card reinsertion)\par \pard\plain \qj\fi180\sa240\keep \f20 If your application happens to be open when the user removes the card, the sequence of calls will be slightly different:\par \pard\plain \s2\li360\sa240\keep \f20 \bullet user unlocks the card with your app open\line \bullet RemoveScript called\line \bullet invalid reference encountered \endash RemoveScript halts\line \bullet user reinserts card\line \bullet RemoveScript continues\line \bullet app is closed \endash ViewHideScript and ViewQuitScript called\line \bullet InstallScript runs (due to card reinsertion)\par \pard\plain \qj\fi180\sa240\keep \f20 Even if you fix your RemoveScript so it doesn't use any invalid references there's not too much you can do about the occurrence of the reinsertion message during this second sequence. After your RemoveScript executes, your application is sent a Close message. Searching for the Close method will cause access to an invalid reference, the _proto slot of your base view. Your base view's _proto slot references its template which is in your package.\par \pard \qj\fi180\sa240\keep The purpose of presenting these detailed sequences is not so you'll write your code to rely on them. You definitely should not. These details may change in future products.\par \pard \qj\fi180\sa240\keep The two points you should note are:\par \pard\plain \s2\li360\sa240\keep \f20 \bullet Your RemoveScript and ViewHideScript/ViewQuitScript can run in any order. Don't assume that the RemoveScript runs last.\line \line \bullet The one case where it's ok to trigger the card reinsertion message is when the user removes the card while your application is open. This one is presently beyond your control.\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 TotalClone() and EnsureInternal()\par \pard\plain \qj\fi180\sa240\keep \f20 The weapons at your disposal to fend off the reinsertion dialog are the global functions TotalClone and EnsureInternal. They are cousins of the global functions Clone and DeepClone. \par Most people grasp the difference between Clone and DeepClone. Clone copies only the "top level" of an object, while DeepClone copies all the objects it references, and all the objects those objects reference, and so on. So the question that arises is: "If DeepClone copies everything, what does TotalClone do?"\par The answer is that DeepClone doesn't actually copy everything. It copies everything necessary to ensure that no change you make to a DeepClone of an object will affect the original. However, a DeepClone of an object may still share ce rtain parts with the original \endash parts that aren't normally destructively changed like symbols. Currently, there are no NewtonScript functions that destructively change a symbol, so symbols aren't copied by DeepClone. A common example would be the symbols used as slot names by frames. There is no reason for DeepClone to copy them and not copying them saves memory.\par This is not normally a problem, unless the original object happens to reside in your package. Your package can be removed (card removed or Remove Software) leaving your DeepClone with invalid references. To deal with this problem, the function TotalClone is provided. It makes a "deep" copy of an object, but more importantly, it guarantees the object it returns resides entirely in internal RAM or ROM.\par There is a related function, EnsureInternal, which simply guarantees the object it returns is entirely in the internal RAM or ROM. It may or may not return a new object. It only copies as necessary to ensure the object is in internal RAM.\par Strictly speaking, packages in Newton's internal store are already in internal RAM. So to be precise I should say TotalClone and EnsureInternal guarantee the objects they return are entirely in the NewtonScript heap or the system ROM . The terminology gets a little sloppy here. Generally, when someone talks about to an object being internal, they mean it's in the NewtonScript heap or system ROM. If you want to nit-pick, you can argue that EnsureInternal should have been called EnsureInNSHeapOrROM.\par Normally, the function you want to use is EnsureInternal. This is because usually the only thing of importance is that the result reside internally, not that you get an entirely new object. I've noticed a lot of people using TotalClone when EnsureInternal would have been sufficient. EnsureInternal may use less memory if parts of the object are already in internal RAM. In practice, you may find that EnsureInternal often ends up making a "TotalClone" of the object. I still recommend using EnsureInternal beca use it saves memory in some cases and it clarifies that your code relies only on the result being internal and not on it being a completely new object.\par Here are some examples contrasting EnsureInternal and TotalClone. Figure 3 shows a simple data structure consisting of {\f22 frame1}, which contains a reference to {\f22 frame2} . Table 1 shows how TotalClone and EnsureInternal behave differently (with respect to what is copied) depending on whether or not {\f22 frame1} or {\f22 frame2} are entirely internal.\par \pard \qc\fi180\sa240\keep {{\pict\macpict\picw145\pich63 0220003b001a007a00ab001102ff0c00ffffffff001a0000003b000000ab0000007a00000 000000000a0008200a10064000a53504e5403e80001000000a10064000e53504e540cd000 3b001a007a00ab00a10064000a53504e540bb80001000000a10064001a53504e540c26003 b001a007a005600040002ffffffffffffff ff00a10064000a53504e540c940000000000a10096000c050000000200000000000000000 1000a003b001a007a00ab002c000a001607436f757269657200030016000d0009002e0004 00000000002b1f47027b0d00002a0b0820736c6f74313a0d002a0b0b20736c6f74323a203 4320d00002a0b0a202f2f6672616d65310d 002a0b017d0000a0009700a10064000a53504e540bb80001000000a10064001a53504e540 c26003b006f007a00ab00040002ffffffffffffffff00a10064000a53504e540c94000000 0000a10096000c050000000200000000000000002800470074027b0d00002a0b0b20736c6 f74413a20245a0d00002a0b010d00002a0b 092f2f6672616d65320d00002a0b017d0000a0009700a10064002253504e540cee0002001 000560000002600000056000000000000000000000000000000a10064000a53504e540bb8 0002000300a10064000e53504e540c9e004f0048004f007200a0008c0022004f00481e000 071001e004a006600540072004f00660054 0066004f0072004a0066004f006600a0008d00a10064000653504e5403e900a0008300ff} }\par \pard\plain \s6\qc\fi180\sa240\keep \f20 Figure 3 - Data Structure for Table 1\par \trowd \trgaph80\trleft2340 \clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx3240\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx4040\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0 \cellx6100\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx8260\pard\plain \qc\keep\intbl \f20 {\fs20 frame1\cell frame2\cell TotalClone\cell EnsureInternal\cell }\pard \intbl \row \trowd \trgaph80\trleft2340 \clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx3240\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx4040\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx6100\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx8260\pard \keep\intbl {\fs20 internal\cell internal\cell clone frame1 & frame2\cell no cloning\cell }\pard \intbl \row \pard \keep\intbl {\fs20 internal\cell external\cell clone frame1 & frame2\cell clone frame1 & frame2\cell }\pard \intbl \row \pard \keep\intbl {\fs20 external\cell internal\cell clone frame1 & frame2\cell clone frame1 only\cell }\pard \intbl \row \trowd \trgaph80\trleft2340 \clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr \brdrs \clshdng0\cellx3240\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx4040\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0\cellx6100\clbrdrt\brdrs \clbrdrl\brdrs \clbrdrb\brdrs \clbrdrr\brdrs \clshdng0 \cellx8260\pard \keep\intbl {\fs20 external\cell external\cell clone frame1 & frame2\cell clone frame1 & frame2\cell }\pard \intbl \row \pard\plain \s6\qc\fi180\sb240\sa240\keep \f20 Table 1 - TotalClone Vs EnsureInternal\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 Fifty Ways to Leave Your Reference\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Leaving a Direct Reference Around\par \pard\plain \qj\fi180\sa240\keep \f20 This is the most obvious case. You tuck a reference somewhere and then forget to clean it up later. For example, in your ViewSetupFormScript you do something like:\par \pard\plain \s3\li180\sa240\keep \f22 AddArraySlot(SoupNotify,kMySoupName);\line AddArraySlot(SoupNotify,kAppSymbol);\par \pard\plain \qj\fi180\sa240\keep \f20 The two elements you're adding to the SoupNotify array are references to your package \endash a reference to a string literal and a reference to a symbol. If you entirely forget to remove these two elements, you'll corrupt SoupNotify. You may be thinking, "That's pretty obvious. I would never do that," but there's still a way you can get caught. \par You also have to think carefully about when you plan to clean up. If you wait until your RemoveScript runs it may be too late. At that point your package is gone and the references are invalid. If you knew the indexes of your two elements of SoupNotify you could remove them with ArrayRemoveCount without actually having to access them. Unfortunately, in the case of SoupNotify you can't know those indexes with certainty. They might have changed from their original positions as other applications removed their elements from SoupNotify. To find your element you need to search SoupNotify, but even a simple pointer equality check will cause the bad references to be accessed and trigger the reinsertion message.\par One possible solution to this dilemma is to remove the elements in your ViewQuitScript. You can be sure the references are valid when ViewQuitScript executes. Another solution would be to call EnsureInternal on the elements before adding them. This will allow you to safely remove them during your RemoveScript.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Corrupting a Frame with an Invalid Slot\par \pard\plain \qj\fi180\sa240\keep \f20 This is probably the most common and most subtle of the errors. When you add a slot to a frame, you have to consider the symbol used as the slot name and possibly the actual contents of the slot. I commonly see someone creating a slot, being careful to call EnsureInternal on its contents, and then later using RemoveSlot to clean up. Two common examples are installing formatting frames in the root view and installing routing frames in the Routing global variable. Here is some typical code:\par \pard\plain \s3\li180\sa240\keep \f22 //install routing frame (typical error)\line Routing.(kAppSymbol) := EnsureInternal(myRoutingFrame);\line ---\line //clean up - (in RemoveScript)\line RemoveSlot(Routing,kAppSymbol);\par \pard\plain \qj\fi180\sa240\keep \f20 The above installation code does exactly the opposite of what it should have done. It uses EnsureInternal on the contents of the slot it's creating and not on the slot symbol. When the remove script runs, the reinsertion message will appear because the symbol used as the slot name in the global routing frame has become an invalid reference. The content of the slot doesn't matter, it isn't touched. It's the slot name that's the problem.\par Once a frame is corrupted in this way, accessing any slot can be a problem. This is because accessing a slot requires searching the frame for that slot. If the search comes across an invalid reference, boom! You might notice situations in which some slots are safe to access and some aren't. You shouldn't take advantage of this observation. The details of slot access may change in future implementations of NewtonScript. If any slot symbol is corrupt, the whole frame should be considered corrupt. \par \pard \qj\fi180\sa240\keep The above installation code can easily be corrected as follows:\par \pard\plain \s3\sa240\keep \f22 //install routing frame (works)\line Routing.(EnsureInternal(kAppSymbol)) := myRoutingFrame;\par \pard\plain \qj\fi180\sa240\keep \f20 This may look a bit strange, but it solves the problem. Notice that there is no need to call EnsureInternal on {\f22 myRoutingFrame} because RemoveSlot doesn't access the contents of the slot being removed.\par \pard \qj\fi180\sa240\keep A subtle variation on this problem is changing the contents of an existing slot. You might run into a situation where you're just changing an existing slot. You might automatically conclude that you don't have to call EnsureInternal on the slot symbol because you're not adding a new slot. Consider the following example:\par \pard\plain \s3\li180\sa240\keep \f22 //f is a frame: \{_proto: \{slotA: 42\}\};\line f.slotA := nil;\line //f is now: \{slotA: nil, _proto: \{slotA: 42\}\};\par \pard\plain \qj\fi180\sa240\keep \f20 Recall that the first time you change a slot inherited from the proto chain, a new slot is created. So you may actually be creating a new slot. Consequently, you need to consider using EnsureInternal on the slot name. In the above example you could use:\par \pard\plain \s3\li180\sa240\keep \f22 f.(EnsureInternal('slotA)) := nil;\par \pard\plain \qj\fi180\sa240\keep \f20 You can run into this problem changing any frame with a _proto slot. Some practical examples would be the root view and the UserConfiguration global variable (which inherits its default values from its proto chain). \par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 AddDelayedAction and AddDeferredAction\par \pard\plain \qj\fi180\sa240\keep \f20 I once ran into a case of a developer who would get a -10401 error only if he removed the card while his application was running. It turns out that he was using AddDeferredAction in his ViewQuitScript. When you remove the card with the application open, the deferred action is run after the card is gone. I suppose if I closed his application and then immediately unlocked his card I might be able to achieve the same error if I was quick enough.\par The problem was that the co de for the deferred action was inside his package. He got a -10401 error instead of a reinsertion message because the deferred action ran after the card removal was complete. In general, you have to be concerned about any deferred actions you set up as par t of your ViewHideScript/ViewQuitScript code and any you set up from your RemoveScript.\par The solution is to EnsureInternal the closure you pass to AddDeferredAction, but you don't want to be passing any old closure to EnsureInternal. Closures ar e more than function pointers. At the time they're created they close over the current lexical environment and the current receiver (self). This means when you EnsureInternal a closure you may be cloning a lot more than just the compiled code.\par For example, if in your ViewQuitScipt you tried something as simple as EnsureInternal(func() 42) you'd get an out of memory error. Why? Because self (your base view) has a _parent slot that points to the root view. So you'd end up trying to make an interna l copy of the root view.\par You probably only want to EnsureInternal closures with empty lexical environments and receivers. Closures created at the build-time "top level" fit the bill. Examples of these would be evaluate or script slots that are initialized to func(\'c9)\'c9 . . So a solution to the above developer's problem was to define his deferred action in a slot in his base view and then EnsureInternal the contents of this slot and pass it to AddDeferredAction.\par Adding deferred actions in your ViewQuitScript is a pretty strange thing to do anyway. I can't think of any reason it why would be necessary. The real solution to this developer's problem was to eliminate that code entirely. However, delayed actions are a different story.\par Since a delayed action executes after a specified time delay, anything could happen between when you call AddDelayedAction and when the closure you passed in gets executed. This means that to be safe, you have to call EnsureInternal on any closure you pass to AddDelayedAction. Of course, the above notes on using EnsureInternal on closures still apply.\par In case you were wondering, normally you never have to worry about EnsureInternal when using ViewIdleScripts. The system takes care of shutting down your idle scripts when your view is closed. They won't be called after your package has been removed. \par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Touching theForm or Your Base View in the RemoveScript\par \pard\plain \qj\fi180\sa240\keep \f20 Your InstallScript and RemoveScript are passed a single argument, a partFrame. One of the slots in partFrame is theForm. It contains a reference to your base view's templat e. When your RemoveScript is called, theForm will be an invalid reference. Trying to access it will trigger the reinsertion message.\par As a way around this, some people have discovered that when their RemoveScript is called their base view is still in the root view and can be accessed using:\par \pard\plain \s3\li180\sa240\keep \f22 GetRoot().(kAppSymbol)\par \pard\plain \qj\fi180\sa240\keep \f20 This is a bad idea. Under some circumstances you can get away with references to slots in your base view, but it's a risky thing to do. One problem is that the _proto slot of your base view is an invalid reference to its template (theForm). So if your code causes any inheritance to be used, the _proto slot will be accessed and the reinsertion message appears. Even if you know the slot you're after is in the base view (no proto chain search necessary) you're still likely to run into slots whose symbols aren't internal as described above.\par My advice is: do not access your base view in your RemoveScript. However, it is safe to use the following code in your RemoveScript. Notice it doesn't access any slots in your base view or send messages to your base view.\par \pard\plain \s3\li360\sa240\keep \f22 RemovePowerOffHandler(GetRoot().(kAppSymbol));\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Soup Related Problems\par \pard\plain \qj\fi180\sa240\keep \f20 Soup entries are one of the easier cases to handle with respect to invalid references. The system takes care of soup entries for you. You don't have to call EnsureInternal on a frame before passing i t to AddToDefaultStore. However, you may want to Clone it for other reasons. Remember, when you pass a frame to AddToDefaultStore it's destructively changed.\par The entry frames you deal with in your code reside in the NewtonScript heap. They are caches of the actual information in the soup which resides in a user store. That it means it's possible for you to modify one of these frames and taint it with an external reference. However, as soon as you call EntryChange or EntryUndoChanges, the system ensures the entry is internal.\par \pard \qj\fi180\sa240\keep Soup entries are not a problem, but there are some other things you need to watch out for when using soups.\par In general, you want to set the slots you created in your base view to nil in your ViewQuitScript. This will allow these to objects to be garbage collected provided there are no references to them elsewhere. If you forget, it can be especially troublesome to leave references to soups or cursors. Leaving a cursor reference is a common source of -10401 errors.\par \pard \qj\fi180\sa240\keep Another way you can get a -10401 error is with SetInfo or SetAllInfo (both the store and the soup methods). Both the slot symbol and the value you pass to SetInfo need to be internal, as does the frame you pass to SetAllInfo. Use EnsureInternal on these arguments. If not, the info frame can become corrupted. This is not to say the information in the soup will become corrupted, rather, only the frame which serves as a cache for the actual soup data will be corrupted. Rebooting will solve the problem.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Notify Related Problems\par \pard\plain \qj\fi180\sa240\keep \f20 You need to make sure the parameters you pass to Notify are internal. You might have noticed that Notify retains references to the last four messages it displayed and allows the user to scroll through them using the universal scroll arrows. Because of this, you need to ensure that the strings you pass as the second and third parameters to Notify won't become invalid references if your application is removed. The first parameter to Notify is an immediate, one of four pre-defined integer constants, so it's not a problem.\par \pard \qj\fi180\sa240\keep If you mess up, the next time Notify is called it will access an invalid reference and attempt to display a -10401 error using Notify. The result is that the Newton beeps endlessly as Notify keeps trying, and failing, t o display -10401 errors. You can see the -10401 exceptions in the NTK Inspector if you have it connected.\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 Being Too Paranoid\par \pard\plain \qj\fi180\sa240\keep \f20 I don't want you to go sprinkling calls to EnsureInternal throughout your code as a result of reading this article. You need to make sure you understand when and where you need it and use it only when necessary. Otherwise you'll increase your code size and probably waste a lot of RAM. In this section I make some points about when you need and don't need EnsureInternal.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Slot Access\par \pard\plain \qj\fi180\sa240\keep \f20 When people learn that they can corrupt the root view using code like: {\f22 GetRoot().foo := myFormat} they start writing code like: {\f22 y := GetRoot().(EnsureInternal('myFormat))}. When you're simply accessing a slot there is no need to use EnsureInternal. It's only when you're creating a slot that you have to worry.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 InstallScripts and RemoveScripts Execute From Internal RAM\par \pard\plain \qj\fi180\sa240\keep \f20 Your InstallScript and your RemoveScript are copied into internal RAM before they are executed. (This is always true for the applications you make with the current version of NTK. The rules will vary when NTK supports other types of code.) The implication is that you don't have to worry about using EnsureInternal in your InstallScript. (This goes without saying for your RemoveScript because at that point it's too late to use EnsureInternal.) Revisiting my previous SoupNotify example: \par \pard\plain \s3\li180\sa240\keep \f22 AddArraySlot(SoupNotify,kMySoupName);\line AddArraySlot(SoupNotify,kAppSymbol);\par \pard\plain \qj\fi180\sa240\keep \f20 If this code appears in your InstallScript, there is no need to use EnsureInternal. However, it's common practice for InstallScripts to utilize code that's actually stor ed in your package. Two common ways of doing this are with code like:\par \pard\plain \s3\li180\sa240\keep \f22 partFrame.theForm:Install()\line or\line AddDeferredAction( func() GetRoot().(kAppSymbol):Install(),'[]);\par \pard\plain \qj\fi180\sa240\keep \f20 These examples assume there is an Install method defined in your base view's template to handle your application's installation needs. Whether you call it directly in the template or in a deferred action to your base view depends on exactly what you need to do. The second method is probab ly more straightforward to get working. The advantage of keeping the bulk of your installation code in your package is that it lets you keep your InstallScript small. This is important since your InstallScript is copied into memory. Unfortunately, this same technique won't work for your RemoveScript. I f you have to ask why, you need to re-read this article.\par But I digress. The point is: if you keep your installation code in your package, it won't be copied into internal RAM and you will have to use EnsureInternal as necessary.\par A slight variation on the above is that sometimes an InstallScript will need to grab data from theForm. For example, a printing format may be in a slot of theForm. Remember, theForm has not been copied into internal RAM. Any time you get data from theForm you need to consider whether or not you need to use EnsureInternal. In most cases you probably don't, but you should think about it.\par There is yet another variation on the above theme. Your application has no way to access the partFrame that's passed to your InstallScript and RemoveScript. Sometimes people pass the partFrame to an installation method in their base view. Sometimes they even tuck a reference to the partFrame in a slot somewhere. It's sometimes useful to be able to access the partFrame so you can communicate with your RemoveScript \endash f or example, provide it with information it needs to clean up. If your InstallScript puts something in a partFrame slot, there's no problem since the InstallScript is in internal RAM. However, if you've got code in your package operating on the partFrame you need to be careful not to corrupt it. Specifically, make sure to call EnsureInternal on the symbols for any slots you create in the partFrame otherwise you will corrupt it. If you expect the RemoveScript to be able to access an object referenced by one of those slots, the object needs to be internal too.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 ViewSetupFormScript, ViewQuitScript, et al\par \pard\plain \qj\fi180\sa240\keep \f20 Your ViewSetupFormScript, ViewSetupDoneScript, ViewHideScript, ViewQuitScript, etc., aren't copied into internal RAM as your InstallScript and RemoveScript are, in general, no other code is treated specially like the InstallScript and RemoveScript. That doesn't mean you automatically have to use EnsureInternal everywhere. Generally, you don't have to worry about calling EnsureInternal on references that you will clean up in your View QuitScript (or ViewHideScript). This is because your ViewQuitScript is guaranteed to run when your references to your package are valid.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 InstallScript Vs ViewSetupFormScript\par \pard\plain \qj\fi180\sa240\keep \f20 There's a nice symmetry we can observe. If you "do it" in your InstallScript and "undo it" in your RemoveScript there's no need to worry about EnsureInternal. Nor is there any worry if you "do it" in your V iewSetupFormScript and "undo it" in your ViewQuitScript. It's when you break the symmetry that you have to start worrying.\par Unfortunately, you may not get to take advantage of this symmetry. Installing a full-blown application will actually involve a fair amount of code and data . Consider all the IA templates, meta-data specifications, routing frames, formatting frames, etc. You probably will need to keep most of it in your package, and this breaks the symmetry.\par \pard \qj\fi180\sa240\keep As a general guideline, do as much as possible in your ViewSetupFormScript and ViewQuitScript and as little as possible in your InstallScript and RemoveScript. Keeping your InstallScript small conserves memory (recall your InstallScript and RemoveScript are copied into internal RAM). As was noted in the previous section, you can also keep the size of your InstallScript down by using code that's stored in your package. However, it's still important to minimize the work you do in your InstallScript so as not to slow down the card insertion process.\par \pard \qj\fi180\sa240\keep There are some services it makes sense to register with as soon as the card with your application is inserted, such as IA or global Find \endash the user shouldn't have to have your application open in order to use Find or IA . There are other services that you only need if your application is actually open, such as RegisterCardSoup \endash there is no reason you need to be creating soups on every card you see unless your application is open. There are other cases that might be deceiving. Initially, it might seem you only need to be registered with SoupNotify when your application is open. However, the SoupNotify array is also used to notify applications when the user has edited the filing categories. If your application supports filling, y ou probably want to register with SoupNotify right away.\par \pard \qj\fi180\sa240\keep Basically you should put off registering with system services as long as possible and unregister as soon as possible. You need to think carefully about when you will be utilizing system services in order to decide between registering in your InstallScript or in your ViewSetupFormScript.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Minimizing the Depth of Copies\par \pard\plain \qj\fi180\sa240\keep \f20 Sometimes you can get away with using Clone instead of EnsureInternal. Remember, EnsureInternal often ends up making a "deep" copy. For example, maybe you need to make sure a reference to an array doesn't become invalid, bu t you don't care about the elements. Use Clone to make a shallow copy of the array in internal RAM. Watch out. Clone won't copy the class symbol. This means the new array will share its class symbol with the original. Hence, its class can become an invalid reference. Below is a one-liner to make a shallow-internal copy of an array \endash including its class (note that SetClass returns its first argument as its result).\par \pard\plain \s3\li180\sa240\keep \f22 SetClass(Clone(origArray),EnsureInternal(ClassOf(origArray)));\par \pard\plain \qj\fi180\sa240\keep \f20 Frames are a little trickier. Recall that Clone won't copy the slot symbols. So we can't start by simply using Clone to make a shallow copy. Instead, we can create a new slotless frame and then copy over the slots from the original one at a time \endash making sure the slots we create are internal. Below is some code that makes a shallow-internal copy of a frame.\par \pard\plain \s3\li180\sa240\keep \f22 local newFrame := \{\};\line local slot,val;\line foreach slot,val in origFrame do\line \tab newFrame.(EnsureInternal(slot)) := val;\par \pard\plain \qj\fi180\sa240\keep \f20 Building up a frame one slot at a time isn't the most efficient way to do things, but in this case we can't do better unless know ahead of time about the structure of {\f22 orig}{\f22 Frame}.\par \pard\plain \s254\qj\sb120\sa240\keep \b\f20 Never Clone Needlessly\par \pard\plain \qj\fi180\sa240\keep \f20 In general, applications should only do enough copying to make sure they can do their cleanup without accessing an invalid reference. For example, if you're creating a slot in the base view for a printing format, you'll remove the slot in your RemoveScript, but you won't access the slot's contents. So you only need to make sure the symbol you use for the slot name is internal, not the slot's contents.\par \pard \qj\fi180\sa240\keep Another example is adding an element to a global array such as FormulaList. FormulaList is an array of templates used to generate the panels in the built-in Formulas application. Your application can add a panel of its own by adding a template to FormulaList. Later, when it's time to remove the template you added, your RemoveScript must search FormulaList to find the template. Therefore, it's essential that the template doesn't become an invalid reference (yes, simple equality testing, with =, causes references to be accessed). However, there's no reason to make a deep copy of your template to add to FormulaList. You can create a shallow internal copy using the techniques previously discussed. In fact, your RemoveScript will not access any of the template's slots anyway, so a simple Clone should be sufficient (and use less RAM).\par \pard \qj\fi180\sa240\keep If you think carefully about what your code is doing, you should be able to decide when you need to call EnsureInternal, when Clone is sufficient, and when you don't need to use either of them. Of course, you should test your hypotheses thoroughly. It's very easy to overlook something, but don't let this discourage you from trying to reduce the amount of copying your application does. Your users will thank you for minimizing your application's RAM requirements.\par \pard\plain \s255\qj\sb240\sa240\keep \f20\fs36 Conclusion\par \pard\plain \qj\fi180\sa240\keep \f20 The reinsertion message and the -10401 error are two of the most common problems applications have. They can be especially annoying because they're usually discovered when you think you've almost finished . It works "perfectly," except when you try to remove the card. This, combined with the somewhat esoteric nature of the problem, makes for some world-class frustration.\par Unfortunately, there is no simple recipe I can give you. This article has touched on most of the relevant issues. Perhaps some of it even makes sense. My advice is to test your application constantly by unlocking and locking the card it's on . Start this testing early in the development cycle and make changes to your code in small increments. Too often, people don't notice these problems until they're near the end of the project. There's nothing worse than a huge amount of code that doesn't work for some totally mysterious reason. Unfortunately, I frequently find myself in this situation. Typically I'm on the phone trying to talk some developer "off the ledge," usually without the luxury of being able to look at the source with my own eyes. Most of the time I can quickly track down the offending code using the following general guidelines:\par \pard\plain \s2\li360\sa240\keep \f20 \bullet Insert the card and remove it without running your application. If you get the reinsertion message then it's probably something your InstallScript did. Most likely your InstallScript executed instal lation code in your package. Another possibility is that your RemoveScript is trying to use an invalid reference (e.g., {\f22 partFrame.theForm} or {\f22 GetRoot().(kAppSymbol)}{\f22 .foo})\line \line \bullet Insert the card, open your application , close your application, and remove the card. If you get the reinsertion message then you can be pretty sure it's something in your ViewSetupFormScript or ViewSetupDoneScript. It's possible that it's your ViewQuitScript. Judiciously commenting out code should let you narrow it down from here.\line \line \bullet If you reinsert the card in response to the reinsertion message, can you subsequently remove the card? If you can't, it indicates that the problem resides in the InstallScript or RemoveScript. If you can, it indicates it has to do with actually opening the application.\line \line \bullet If it's a -10401 error, make sure your ViewQuitScript sets to nil any base view slots that you have created. Use the Inspector to take a look at your base view. Be especially watchful for references to soups and cursors. Also, check out any deferred or delayed actions and calls to Notify. Remember, if the -10401 occurs when downloading your package, it may indicate a corrupted package. Are you in 32 bit mode? Try building on another machine.\par }