Newton Technology Journal: Volume 2, Number 5
Transcript of Newton Technology Journal: Volume 2, Number 5
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
1/20
Inside This Issue
continued on page 3 continued on page6
Volume II, Number 5 October 1996
NewtonScript Techniques Newton Communications
NewtonScript TechniquesUsing Unit Referencesto SpeedApplication Development 1
Newton CommunicationsNewton 2.0Messaging Enabler -GetYour MessagesMovin 1
Advanced TechniquesMock Entriesfor Debugging 9
Understanding NewtonScriptDebugging Tutorial: Finding andFixing Bugsin an Application 11
Product DevelopmentAvoiding Common UI Mistakes 14
Newton DirectionsGet Connected 15
Communications TechnologyThe High Level Frame Desktop
Integration Library(HLFDIL) 16
Newton 2.0Messaging
Enabler -GetYour MessagesMovinby Jason Rukman, Apple Computer, Inc.
Connectivity! Do you carrya cell phone, pageror possiblysome other device to stayin touch?
If you do, then you would probablylike to
transfer some of thisinformation onto your
Newton PDA. When I have myNewton with me
Id like the information on mypager to go
directlyto myNewton.
The Messaging Enabler isa 2.0transport that
solvesthisproblem byproviding a framework
specificallydesigned for 1-wayand 2-waywireless
messaging. With the Messaging Enabler,
developersare able to get a messaging device
working quickly, easilyand consistentlywith the
Newton. The messaging device will be
integrated with the rest of the Newton system
and Newton applicationsthat support routing.
For the Messaging Enabler to be useful, it
requiresa plug-in driver, called a messagemodule, for a particular hardware device. A
message module must implement a set of APIs
for communicating with the particular hardware
device and the Messaging Enabler looksafter the
rest. (ThisAPI isdistributed with the Messaging
Enabler development kit.)
Your specialtymaybe developing
communicationssoftware. The idea behind the
Messaging Enabler isto remove the user
Using UnitReferencesto
Speed ApplicationDevelopmentby Bob Ebert, Newton DTS, Apple Computer Inc.
THEPROBLEMNTK isgetting faster with each release. WithNTK 1.6.x on a PowerMac, the compilation phase
of even large projectsisamazinglyshort. Unless
you have to do it over and over and over again,
all daylong. Whatsworse, no matter howmuch
faster NTK gets, it still takestime to download
the package, and a PowerMacwont help with
that. I find it annoying to have to wait a minute
or two or twentyto see howa tinychange plays
out in a large package.
Wouldnt it be great to be able to split an
application into smaller projects? You could
build each project separately, saving time both
during compilation and during downloading,
since onlythe smaller part you just edited would
need to be built and downloaded. Separating an
application into piecescould also allowa team of
programmersto work on a project. Each
engineer would produce one part, hack at it untilitsworking, then share it with the team.
HAVENTWESOLVEDTHATPROBLEM?Newton TechnologyJournal volume 1,
number 4, August 1995, contained an article
called Small Parts: A Faster Wayto Develop
Large Applications which addressed this
problem. It showed howto split your application
into separate modulesthat could be compiled
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
2/20
October 1996 Newton Technology Journal
2
The Excitement is Building
I just returned from Macworld Expo/
Boston, where I met a good number of
enthusiasticNewton developersat Developer
Central . Granted, I took some heat for
demoing Newton Toolkit for Windowson a
Pentium (at a Macintosh Expo no less), but as
the implicationsof making Newton
development available to the Windows
communitybegan to dawn on folks, their
eyeslit up. Thisisa verygood thing they
said. I have to agree the possibilitiesare
endless, and the excitement isgrowing.
Speaking of excitement, I want to invite
each of you to the upcoming Fall Newton
DevelopersConference on November 4, 5,
and 6th in San Francisco, California. Bring a
hat to hold onto, asthere will be plentyof
extremelyinteresting news, technical
presentations, hardware demos, and labs. Be
sure to bring your existing code, for reasons
youll hear about later. Be prepared to be
blown away.(Im reallynot verygood atkeeping secrets, can you tell?) For conference
registration information, please visit the
Newton Development Home page at
http://devworld.apple.com/dev/newtondev.shtml
Speakingof secrets, youve probablyheard
bynowthat Apple haswiselyformed the
Information AppliancesDivision, of which
Newton isa part. Jim Groff wasnamed Senior
Vice President of the division byDr. Gil Amelio
in earlyJune. Mr. Groff hasa strongand vocal
commitment to Newton and a rich historywith
Apple which spansa wide range of product
and market areas, from Internet serverstoEducation. SandyBenett wasformallynamed
asVice President of the Newton Systems
Group (he wasactingin the position for quite
some time), and another newface isthat of
Barbara Groth, who nowheadsup the Newton
SolutionsMarketinggroup (formerlyknown as
Developer Relations). Youll be hearingmore
detail on the structure of thiskeygroup in
monthsahead.
In thisissue of the Newton Technology
Journal, we bring you coverage of Newton
Communicationsin the form of Messaging
Enabler and FDILsarticles. We heighten your
programming finesse with articleson User
Interface tipsand howto shorten your
development cycle using unit references. In
the debugging arena, youll find advanced
techniquesusing mock entries, and an
excerpted article on debugging techniques
from the newlyupdated book Programming
for the Newton, 2nd Edition byJulie
McKeehan and Neil Rhodes. And we bring
you important information on the long-
awaited Newton ConnectionsUtilityfor
Newton 2.0.
Keep your eyesopen for Decembers
issue, which no Newton developer will want
to miss. To all of you who spoke with me at
Macworld Expo, thank you for your product
demos, and to all Newton developers, thank
you for your enthusiasm, your belief in your
products, and your ongoing commitment to
Newton. I am confident that all of your hard
work isabout to payoff. The future isvery
bright on the Newton front.
See you at the developer conference!
Jen Dunvan
dunvan@ newton.apple.com
Published by Apple Computer,Inc.
Jennifer D unvan Managing Editor
GerryKane Coordinating Editor,Technical Content
Gabriel Acosta-Lopez Coordinating Editor, DTS and
Training Content
Technical Peer Review Board
J. Christopher Bell,Bob Ebert, D avid Fedor,
Ryan Robertson,Jim Schram, M aurice Sharp,
Bruce Thompson
Contributors
Bob Ebert, Cami Hsu, Julie M cKeehan, N eil Rhodes,
Jason Rukman, Bill Worzel
Produced by Xplain Corporation
N eil T icktin Publisher
W ill Iverson Technical Production Review
InfoG raphix Design/Production
1996 Apple Computer,Inc.,1 Infinite Loop,C upertino,C A95014,408-996-1010. A ll rightsreserved.
Apple, the Apple logo, APD A, AppleDesign, AppleLink,AppleShare, Apple SuperDrive, AppleTalk, HyperCard,LaserWriter,Light Bulb Logo,Mac,M acApp,Macintosh,MacintoshQ uadra, MPW, N ewton, N ewton Toolkit, N ewtonScript,Performa, Q uickT ime, StyleW riter and WorldScript are
trademarks of Apple C omputer, Inc., registered in the U.S. andother countries. AO CE, AppleScript, AppleSearch, ColorSync,develop, eWorld, Finder, O penD oc, Power M acintosh,Q uickD raw, SNA ps, StarCore, and Sound Manager aretrademarks,and AC O T isa service mark of Apple Computer, Inc.Motorola and Marco are registered trademarksof Motorola, Inc.N uBus is a trademark of Texas Instruments. PowerPC is atrademark of International BusinessM achinesCorporation, usedunder license therefrom. W indowsis a trademark of M icrosoftCorporation and SoftWindowsisa trademark used under licenseby Insignia from Microsoft Corporation. UN IX is a registeredtrademark of UN IX System Laboratories, Inc. D eveloper Centralis a trademark of X plain Corporation. CompuServe, PocketQ uicken by Intuit, CIS Retriever by BlackLabs, PowerForms bySestra, Inc.,AC T ! bySymantec,Berlitz,and all other trademarksarethe propertyof their respective owners.
Mention of products in this publication is for informational
purposes only and constitutes neither an endorsement nor arecommendation.A ll product specificationsand descriptionsweresupplied by the respective vendor or supplier. Apple assumesnoresponsibility with regard to the selection, performance, or use ofthe products listed in this publication. A ll understandings,agreements,or warrantiestake place directlybetween the vendorsand prospective users. Limitation of liability: Apple makes nowarrantieswith respect to the contentsof productslisted in thispublication or of the completenessor accuracyof thispublication.Apple specifically disclaims all warranties, express or implied,including, but not limited to, the implied warranties ofmerchantabilityand fitnessfor a particular purpose.
Volume II, Number 5 October 1996
Letter From the Editorby Jennifer Dunvan
Editors Note
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
3/20
Newton Technology Journal October 1996
3
and downloaded separately, but which would still work together. The small
effort to split your application up wastypicallyrecovered in the first dayof
building and downloading smaller pieces. The DTS 1.x Q&Asalso go intodetail on howto split up an application.
One of the drawbacksto using those approachesisthat you have to edit
your code to make the connectionswork properly, then edit it again when
producing a final version. You also need to create global variables, and write
code to hook these globalsinto your app. Even after mastering all that,
getting data from another package into a templates_proto slot isverytricky.
Thisarticle buildson those techniques. Using the unit reference feature
added in the 2.0release of the Newton OS, you can split a large application
into pieceswhich can be built and downloaded separately, or combined into
a single part. Whatsmore, the source filescan nowwork either waywithout
modification.
BACKGROUND: UNITREFERENCESNewin the 2.0release of the Newton OS isthe abilityfor one package to
directlyreference data in another. Actually, youve been able to do thisall
along using run-time referencesfound in global variables, slotsin the root
view, or other places. Whatsnewisthat you can nowhave NTK compile in
referencesto data in other packagesso you wont need to use any
NewtonScript heap space to make the connections.
You mayhave heard of so-calledmagic pointers, which are referencesin
your packagesto objectsin the ROM. Whatsmagic about these pointersis
that the objectsthemselvesare in different locationsin the variousROM
releases. Yet your package still managesto find the right value, no matter
which ROM it loadsin. Magic!
Itsnot reallymagic, of course. Magicpointerswork like handles, theres
a double-dereference involved. EveryROM putsa lookup table for magic
objectsin a special place, and the OS looksup the real reference via the table
when the magicpointer isused.
UNITREFERENCESWORKLIKEMAGICUnit referencesgive the partsin your packagesthe abilityto contain
objectsthat can be referenced like magicpointers. Package A can create an
array, frame, or binaryobject and export it. Package B can have a reference
to that object, and the OS will make sure that when B looksfor the object, it
findsit, so long asA isinstalled. No matter where in memoryA happensto
be!
Unit referencesare more magical than magicpointers. Theresno wayofknowing in advance where in memoryan exporting package will be located,
so theresno easywayto locate the table of referencesfor a given part. But it
happens, and your importing package findsthe correct object.
Nowletsclean up the terminology. Aunitisa group of zero or more
objects, identified bya unique symbol aswell asa major and minor version
number. Apartiswhat NTK typicallyproduces, for example an application
or auto part, and a part can export and import zero or more units. Partsgo in
packages, with zero or more partsper package. (But a package with zero
partsisnt good for much besidesdebugging the OS.) Remember that itsat
the part level that unitsare imported or exported, not the package level.
Unit referencesare great for all kindsof applications. Anytime a bunch o
applicationsneed to share some read-onlydata, code, or objects, you should
consider using unit references. One alternative isputting copiesof theshared data in each package, which wastesmemory. Another alternative is
using a soup, but thatstypicallycomplicated because you need to write code
to make, find, and use the data at run-time. Large data objects, shared
prototypes, widelyused functions, or even modulesfrom other programmers
are all thingsthat might be shared via unit references. Thisarticle focuseson
using them during development to speed the build/download/test cycle.
For more detailson the API for unit references, aswell asdocumentation,
supporting functions, and a cool example, check out the Moo Unit sample
code byMike Engber. Moo Unit isdistributed with the DTS sample code.
BACKGROUND: ANAPPLICATIONEach layout or user proto in NTK normallyproducesonlya single object.
That object ismade available to the rest of the project through the build-time
constant functionGetLayout(filename).It ispossible to create layoutsin NTK that produce more than one value.
BeforeScriptsor afterScriptsin the templatesmaycreate other constants,
build-time global variables, or cause other side effects. While thiscan
sometimesbe handy, I think itsbad form for one layout to relyon side
effects from compilation of some other layout. Layoutsand protosare
primarilydeclarativetheycreate an objectand relying on side effectsof
that objectsconstruction can be confusing. Itseasyto avoid programming
thiswaybycreating text filesof common objectsused bymore than one
layout.
Text filesin NTK can be thought of asnothing but side effects. They
create global variableslike theInstallScript
, or constantslike the
localization frame that are used in other partsof your application. Even with
text filesitsusuallya good idea to have each file produce a small, well-
defined set of values. Thisset can be thought of asthe interface between
that file and the rest of the application.
User protosin NTK actuallydo a little bit more than simplycreate an
object at build time. Theyalso clue NTK into the fact that some new
prototype object exists, which allowsNTK to put an item in the User Proto
popup in the palette. Thiscurrentlydoesnt buyyou anything other than the
abilityto drag out a user proto in the layout view. Well come back to this
later.
Linked Layoutsin NTK can be thought of asa special case of user protos.
Unlike user protos, linked layoutsconstrain thingsso that a layout can only
be placed in a project once. Well come back to this, too.
BREAKINGAPROJECTINTOSMALLERPARTSIll assert that all the inter-file connectionsmade while building your
project are accomplished via build-time constants. Thismaynot alwaysbe
so, but itsa useful wayof thinking about your projects, especiallyfor the
purpose of splitting it into pieces.
Anyplace where an object isshared onlyvia a constant isa good place to
split up an application. You do thisbymoving the protos, layouts, or text
filesout of the main project and into a newproject of their own. Thisnew
project will create an auto part that exportsthe shared objects.
continued from page 1
Using Unit Referencesto Speed Application Development
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
4/20
Newton Technology Journal October 1996
4
Thatsreallyall you need to know. That idea, along with the unit
reference documentation, will let you break your big packagesinto smaller
onesthat can be downloaded individually, vastlyreducing the time it takesto
build, download, and test anyone of them.
But keep reading. The rest of the article will describe one wayto create the
interface between the projectsso that no existingcode needsto change. It will
also describe some thingsI do to help with debugginga project built thisway.
CONSTANTAGONIZINGFor constantsprovided via text files, either withDefConst or the
constant keyword, both the code that definesthe constant and thecode that usesthe value of the constant are using the same symbol. This
seemsobvious. It wouldnt work anyother way!
Lessobviousisthat thisistrue for layoutsand protosaswell. Earlier I
mentioned that NTK providesaccessto layoutsand protosthrough the build
time constant functionGetLayout. The old waywasto use a constantnamedlayout_filename, and thisisstill supported. In fact, NTK 1.5and1.6use the constant namedlayout_filenameto implement theGetLayout function. The onlything a layout or proto reallyproducesisa constant with the special name.
When sharing an object via unit references, you could name the reference
anything you like. However, the symbol thatsthe name of the constant, e.g.
layout_filename, turnsout to be an excellent choice. Itsa goodchoice because all your code that usesthe object isalreadywritten to use
that symbol, and the name in the unit reference declaration will be the only
commonalitybetween the exporting project and the importing project.
After the project issplit, the code that definesthe constant isin a different
project than the code that usesit, so well actuallycreatetwoconstants, onein each project. Byusing the same symbol for the namesof them in both
projects, none of the existing code needsto be edited.
Build-time global variablesdont fit into thisscheme. ThatsOK, because
build-time globalsarent the right tool for thiskind of project design. Build-
time constantsfill the same need, and are handled better bythe compiler.
There are timeswhen a build-time global variable isthe right thing to use to
solve a problem, but those casesdont require the global to be shared
between projects, so theyre irrelevant to thisarticle.
USINGUNITREFERENCESThe core of the unit reference mechanism isimplemented bythree
functions. DeclareUnit tellsNTK that a unit isbeing used, the majorand minor version of the unit, and the namesof the objectswithin the unit.
It must be called byboth the importing and exporting projects.
DefineUnit definesthe objectsthat the unit will contain, and iscalledonlybythe exporting project. UnitReference givesyou a magicreference to an imported object that will be hooked up at run time bythe
OS. UnitReference isneeded in the importing application, though itcan be used bythe exporter aswell.
DeclareUnit requiresa declaration frame. Thisisa frame thatdeclareswhat will be shared. The namesof the slotsprovide the namesfor
the objectsin a unit, and the valuesof the slotsare unique integers. The
exporting project must provide a frame with unique sequential integers
starting with 0. Importing projectsare allowed to have gaps. Thisallowsyou
to keep some objectsprivate byremoving their entriesfrom the declaration
frame when given to an importer. Read the unit reference documentation in
the Newton 2.0Q&Asor the Moo Unit sample code for more detail on how
unit referenceswork.
THEINTERFACEFILESince were using unitsfor development only, we dont need to worry
about which objectsare publicand which are private. The exporting project
and the importing project will share the same declaration frame for a unit.
Itsconvenient to put the declaration frame and the code that usesit into a
text file, which I call aninterface file.
The interface file well create will be used in both the exporting project
and the importing project. Again, thisisnt a requirement for using unitreferenceswith NTK, but itsa veryconvenient wayto make sure the two
partsstayin sync. Hereswhat an interface file will contain:
constant kPart1Sym := |Part1:EBERT|;constant kPart1Declaration := {
layout_protoFoo: 0,layout_AboutSlip: 1,kMungeAStringFunc: 2,
};DeclareUnit(kPart1Sym, 1, 0, kPart1Declaration);
The symbol inkPart1Sym isthe name of the unit, and must beunique in the Newton, so a registered signature isused. You should put this
same symbol in the app symbol field of the auto partsproject preferences.
Ill tell you whyin a moment.
Im specifying three thingsin thisunit: a user proto, a layout, and a
constant that happensto contain a function. The unit hasmajor version 1,
and minor version 0. I never change these numbersduring development.
Heressome additional code that I put in myinterface files:
if kAppSymbol kPart1Sym then// building importing project, so create constantsbegin
DefGlobalFn(ImpureUnitRef,constantFunctions.UnitReference);
foreach slot, value in kPart1Declaration doDefConst(slot, ImpureUnitRef(kPart1Sym, slot));
end
Thiscode createsa constant for each slot in the unit reference declaration
frame, but onlyfor importing projects! The exporting project alreadyhasthe
constantsin the text files, layouts, or user protos. Thatswhywe made the
unit symbol the same asthe appSymboltestingkAppSymbol againstthe unit symbol isan easywayof telling if the code isbeing compiled in the
exporting or an importing project.
Thiscode also doessomething unusual. UnitReference isaconstant function, and so it can onlybe called with constant arguments. In
order to make the loop work properly, we need to call the function with the
slot variable from the loop. So we cheat and define a newnormalglobal function calledImpureUnitRef thatsthe same asthe constantfunctionUnitReference. Thistrick worksin NTK 1.5and 1.6, but itsnot guaranteed to work in the future.
Note that exactlythe same thing could be accomplished, in a supported
way, like this:DefConst(layout_protoFoo,
UnitReference(kPart1Sym, layout_protoFoo));DefConst(layout_AboutSlip,
UnitReference(kPart1Sym, layout_AboutSlip)DefConst(kMungeAStringFunc,
UnitReference(kPart1Sym, kMungeAStringFunc)
Thismayseem simpler, and even shorter for thisexample. However, I
dont do it thiswaybecause it requiresme to edit more code everytime I
add, remove, or change the name of a shared object. If you use the loop, the
onlything in the interface file that needsto be edited asthe projectschange
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
5/20
isthekPart1Declaration frame. I think thisissafe becauseduring development I typicallyupgrade NTK much lessfrequentlythan I edit
the contentsof myunits.
THEEXPORTINGPROJECTTheresa little more code that needsto be written to make it all hang
together. The exporting project needsto actuallyspecifythe objectsto
export. Create a newtext file onlyfor the exporting project with thefollowing code:
DefConst(kPart1Objects, {//:
layout_protoFoo: layout_protoFoo, // oldlayout_AboutSlip: GetLayout(AboutSlip), // newkMungeAStringFunc: kMungeAStringFunc,
});DefineUnit(kPart1Sym, kPart1Objects);
Thatsit! You mayask Whycreate the constantkPart1Objects atall? Whynot just put the frame right in the call toDefineUnit and bedone with it? That would work fine, but once again I do a little bit more.
Hereswhat else I put in the exporting projectsdefinition file, strictlyfor
debugging:
if kDebugOn thenbegin
InstallScript := func(partFrame, removeFrame)begin
DefGlobalVar(EnsureInternal(kPart1Sym),kPart1Objects);
foreach slot, value in kPart1Objects doDefGlobalVar(EnsureInternal(slot), value);
end;RemoveScript := func(removeFrame)
beginforeach slot, value in GetGlobalVar(kPart1Sym) do
UndefGlobalVar(slot);UndefGlobalVar(kPart1Sym);
end;end;
What thisdoesiscreate a bunch of run-time global variables. One of the
variableswill have the same name asthe unit, in thiscase
|Part1:EBERT|, and will be a frame with all the exported objects.TheUnitReference function doesnt work at run-time, so withoutsticking a reference to the exported objectsin some easilyaccessible frame it
could be hard to locate them later.
The rest of the globalseach have the same name asthe objectsbeing
exported. Note that I dont include myregistered signature in the namesof
each of these constants. That meanstheressome chance one of mynames
will collide with some system object. I typicallyname thingsesoterically
enough to prevent this. Itsunlikelythat a system object will be called
layout_protoFoo, but you should keep the danger in mind if youdo the same thing.
Youre probablyasking Whyeven bother creating all those individualconstants? Surelyhaving the valuesavailable via the one global frame is
sufficient? I create the extra globalsbecause Im lazy. I like to prototype
code in the inspector, to get it more or lessworking before I make it part of a
project. Global variablesand constantsare accessed using identical syntax.
Having the global variable available at run time for the inspector with the
same name asthe constant thatsavailable at build time for the compiler
meansI can copy/paste code between the inspector and the project and not
edit it. call kMungeAStringFunc with (YourName)worksin either place.
If you havent caught on yet, I like it a lot when the same code worksin
different environmentsor when put together different ways, especiallywhen
no editing isnecessary. Im a verylazyprogrammer.
ABOUTUSERPROTOSANDLINKEDLAYOUTSUser Protosdo a wee bit more than just provide a constant. When a user
proto isin a project, NTK knowsto put itsname in the palette so you can
drag one out. After the split, a user proto mayno longer be in the same
project asthe code that usesit. So what do you drag out?I drag out aprotoFloater instead, then add an after script to fix
up the contentsof the_proto slot. Anypredefined proto would work,butprotoFloaterjust happensto be on the palette and not add anyextra default slots. TheafterScript lookslike this:
thisView._proto := GetLayout(protoFoo);
The same can be done for linked layouts. After the split, the linked layout
mayno longer be in the same project asthe layout itslinked to.
protoFloater to the rescue again! Just drag out aprotoFloater instead of a linked layout, and have theafterScript replace the _proto slot:
thisView._proto := GetLayout(AboutSlip);
Thisactuallydoesnot produce the same result asa real linked layout. We
end up with an extra level of_proto inheritance that wouldnt be therewith normal linked layouts. I t ispossible to completelysimulate what NTK
doeswhen it linksa layout. However, fullyintegrating a declared linked
layout requiresunderstanding of the Newton viewsystem declare
mechanism, which isbeyond the scope of thisarticle. Using a
protoFloater isthe simplest solution, since it letsyou declare theviewsin NTK, just like you would with linked layouts.
SUMMARYIt takesjust a fewsimple stepsto split a project up into separate
compilation unitsthat will exist at run time asseparate packagesand share
objectsvia unit references. The stepsare:
Remove the layouts, protos, or text files fromthe main project.
Put themin a newproject that produces an auto part.
Create the interface file containingeverythingthats shared.
Place it at the beginningof the exportingproject.
Create the definition file for the newproject.
Put it at the end of the exportingproject.
Build and download the exportingpackage.
Add the interface file at the beginningof the main project.
Build and download the main package.
Everything should end up working exactlyasit did before. Notice that you
didnt edit anyof the source layouts, protos, or text filesat all! (Okay, except
maybe to clean up the_proto slotsfor user protosor linked layouts.)
October 1996 Newton Technology Journa
5
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
6/20
NEXTSTEPSFor interim or beta releases, you can make the main project a multi-part
package that containsall the exporting partsaswell asthe main part, so your
beta usersonlysee one package. Remember that the unit reference
mechanism workson a part-by-part basis, so theresno reason the exporting
part and the importing part cant be in the same package.
When youre readyfor your final build, you can just drop the source files
right back into the main project. Put them right where the interface file was,and remove the interface file from the main project. Thistime you dont
have to edit anything at all, even trivially.
Theresactuallyno compelling reason to ever put the filesback in a single
part. The code will all work fine asa multi-part package. I have a suspicion
that performance will improve if everything isin one part. I believe this
because unit referencesmust cost something, but I have not measured the
costs. The localityof the package (in other words, which objectsare next to
which other objects) will also change when switching from separate packages
to a multi-part package to an all-in-one package, and thiscan affect
performance. I recommend trying the variousconfigurationsand choosing
the one you like best.
A BUGTOWATCHOUTFORThere isa bug with unit referencesin the 2.0OS. Sometimeswhen an
importing package isinstalled before an exporting package, the unit
referencesare not properlyconnected. When thishappens, an exception will
be thrown when the bad reference isfollowed bythe importer. You can work
around the problem byreinstalling the importing packages. Bythe time this
ispublished, Apple Computer will probablyhave released a system update
that fixesthisbug, so that you can re-download an exporting package manytimeswithout touching the importer.
CONCLUSIONWith the invention of unit references, itsnoweasier than ever to split a
large application into separate compilation units. Whatsmore, these units
can be put in individual packagesand downloaded separately. Over a full
project development cycle, thiscould amount to daysor even weeksof your
time, much lessthan the time needed to split up the application. The
technique also encouragesa good coding discipline, and can be used to allow
teamsof programmersto work together on large applications.
interface requirement from the Original Equipment Manufacturer (OEM).
Thisallowsa consistent user interface for all wirelessmessaging productsthat
use the Messaging Enabler.
Is it for you?
Of course, the Messaging Enabler wont be suitable for everymessaging
system. It hasbeen designed to enable asmanyof the wirelessmessaging
systemsaspossible. If you want to enable a piece of hardware for the
Newton platform, then it maybe worth using the Messaging Enabler if the
hardware can receive, and possiblysend, messageswirelessly(for instance
pagers, wirelessPC cards, etc.).
A good understanding of routing isrecommended for developersusing
the Messaging Enabler or writing a message module. Although an
understanding of transportsmaybe helpful when writing a message module,
it isnot required. You can find information on routing and transportsin the
Newton Programmers Guide: Communications.
The Messaging Enabler doesmost of the work for you, so that you can
have your hardware up and running assoon aspossible. The exciting
featuresof the Messaging Enabler are covered below.
Message moduleshave manyoptionsthat maybe customized so you can
support featuresspecificto the messaging device being used.Most Newton applicationsthat support routing can use the messaging
device via the Messaging Enabler with no changes. Thisisdue to the
NewtonScript routing mechanism. Applicationscan also be designed to
control the Messaging Enabler directlywhich isideallysuited for applications
targeted to a vertical market.
Features
The following list of featuresshould give you a better idea of some of the
functionsprovided bythe Messaging Enabler:
Standardized preferencesfor wirelessmessaging.
Figure 1: Messaging Enabler Preferences
Device specificpreferences. Note that not all of these preferenceswill
necessarilybe displayed for each device.
Figure 2: Device Specific Preferences
NTJ
October 1996 Newton Technology Journal
6
continued from page 1
Newton 2.0 Messaging Enabler -Get your MessagesMovin
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
7/20
Newton Technology Journal October 1996
7
Send routing slip(s).
Figure 3: Paging Routing Slip
Paging addressdata definitions. Thisextendsthe in-built addressdata
definitions.
Figure 4: Pager Address Listpicker
Message replying. Some 2-waymessaging devicescan replyto received
messages, for instance the Motorola Tango .
Figure 5: Message Reply Picker
Automaticmessage retrieval. Automaticcontrol and combination of
multi-part messages.
Text message viewing/editing/and put away.
The following message showsan item in the In Box made up of two
combined messages.
Figure 6: Displayed In Box Message
Manage and control the I/O Box.
User statusfeedback.
Howit ticks
Figure 7: Messaging Enabler Hierarchy
Asthisdiagram showsthe Messaging Enabler fitsin at the same location
in the Newton communicationslayering asa 2.0Transport.
Installinga message module
To add a message module to the system, you create an auto part. This
meansthat when a message module isinstalled, it addsservicesto the system
but doesnot add an application to the extrasdrawer; however, an icon is
added to the Extensions folder. You define a message module based on the
prototype, protoMsgModule. To add the defined message module tothe system, you call theRegMsgModule platform file function fromyour auto partsInstallScript function with the template you havedefined.
call kRegMsgModuleFunc with (kAppSymbol,partFrame.partData.TestEnabler
);
To unregister the message module you need to supplytwo part framefunctions: DeletionScript and RemoveScript. The DeletionScript function willcall the DeleteMsgModule platform file function to remove anypreferences
for the message module, and also ensuresyour message module
RemoveScript iscalled.
SetPartFrameSlot(DeletionScript,func() begin
call kDeleteMsgModuleFunc with (kAppSymbol
);end
);
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
8/20
In yourRemoveScript of the auto part you should deregister themessage module bycalling theUnRegMsgModule platform filefunction:
call kUnRegMsgModuleFunc with ( kAppSymbol );
Workingwith callbacks and events
Most of the methodsdefined inprotoMsgModule take a callbackasone of the parameters. The Messaging Enabler will call methodsthat you
override inprotoMsgModulewhen the Messaging Enabler needstoperform a particular operation. For example: When the Messaging Enabler
needsa message from the message module, it maysend the
GetNextMessagemessage, which could be implemented asfollows:
GetNextMessage := func( callBack ) begin........ // go get the next message....:doEvent(
kEV_PROGRESS,{ type: vBarber,
statusText: Almost done...}
);....:doCallBack(
callBack ,kRES_SUCCESS,message // your retrieved message
);
end; // GetNextMessage
Note that the callsto the internallydefined methodsof
protoMsgModule,doEvent, anddoCallBack. ThemethoddoEventwasused to change the statusdisplay. The MessagingEnabler providesa default statusdisplaybut bysending eventsto the
Messaging Enabler thiscan be customized. Sending thedoCallBackmessage isrequired to inform the Messaging Enabler when the operation for
GetNextMessage hasbeen completed. Thisalso returnsthe resultfrom the requested operation.
You maysend other eventsto the Messaging Enabler to let it knowwhen
certain thingshappen. For example, if a newmessage hasbeen received, you
would send akEV_MESSAGE event to alert the Messaging Enabler toread the message. You would do thisbysending thedoEvent message.
Need to send messages?
To support sending you need aSendOptions frame and aSendMessage method. TheSendOptions frame definesoptionsfor sending messages. The Messaging Enabler will call the
SendMessagemethod when a newitem needsto be transmitted. The
main slot required for theSendOptions frame isrouteSlipType. Thisdefinesthe addressing type to use whensending. The Messaging Enabler addsa paging data definition to the system.
For more information about data definitions, please see the Stationery
chapter in theNewton Programmers Guide: System Software.
A newitem will be added to the action picker based on the
SendOptions frame contents. A typicalSendOptions framemight be similar to the following:
{ routeSlipType: |nameRef.people.pager|,replyTypes: [ ack, user, canned ],dataTypes: [ text, frame ],group: page,
groupIcon: ROM_RoutePageIcon,groupTitle: Page
}
Figure 8: Notepad Routing Picker
Thismeansthat anyNewton application that supportsrouting for either
text orframe datatypeswill nowbe able to send thisdata asa page.See the Routing Interface chapter in theNewton Programmers Guide:
Communications.
Whats your preference?
The Messaging Enabler providesseveral different mechanismsfor
controlling user preferences. The main preference slip asseen in Figure 1
containsseveral itemsthat will onlybe visible if your message module
overridescertain prototype slots. For example, the first option, When
receiving, will onlybe visible if your message module setsthe
dirSupport slot totrue. (Note, however, that thislabelpicker maystill be visible if another installed message module hasthisset.)
A separate viewdisplaysthe hardware preferencesfor each messaging
device. The Messaging Enabler providesfive genericpreferencesthat you
mayuse asseen in Figure 2. These preferencesare veryeasyto set up. All
that isneeded isan arrayof stringsthat become the optionsfor each
preference (such asthelabelCommands for thelabelPicker).For example, you could setsoundStrings to the following array:
[ Off, Tunes, Annoying, Loud ]
to correspond with the hardware optionsfor the particular messaging device.
Note that the first arrayitem will be the default for each of the preferences,
so it isimportant to make the most reasonable preference setting the first
item in the array. The Messaging Enabler determineswhen these
preferencesneed to be set and will call theSetConfigmethod of themessage module at the appropriate time.
A third wayto provide user preferencesgivesmore customization control,
but also requiresmore work. Provide your own preference viewtemplate.
You might need to do thisif there issome special setting that isnot covered
byanyother preference controls. You supplythisviewtemplate in the
prefsTemplate slot of your message module.Asyou can see, there are several levelsof control for the user preferences.
In most cases, it isimportant to remember that lessisoften better. Most userswork better with devicesthat function in an expected manner, rather than
having to set a bunch of preferencesto get them to work a particular way.
Controllingthe MessagingEnabler.
The Messaging Enabler mayalso be controlled byan installed Newton
application. Thisfeature isintended primarilyfor vertical applications(such
asa health-care dispatch application) that would need to set the preferences
explicitly.
To change the Messaging Enabler preferencesan installed Newton
application would call theTransportNotifyglobal function.
October 1996 Newton Technology Journal
8
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
9/20
Newton Technology Journal October 1996
9
For example:
TransportNotify(MsgEnabler,ChangeConfig,[ callBack,
{ disable: true,autoStatus: nil,hideItems: nil,
},
{ deviceSym: MM_msgModule,powerIndex: 1,portIndex: 2
}]
);
Thisdoesthe following:
Disablesthe user accessto the Messaging Enabler preferencesso they
cannot be changed.
The statusdialog will not be automaticallyopened. ( The user can still see
the statusif it isselected from the NotifyIcon at the top of the screen.)
The Messaging Enabler itemswill not be displayed in the I/O Box.
The installed message moduleMM_msgModulewill have itspreferencesset to the second item in thepowerStrings arrayandthe third item in theportStrings array.
Asyou can see, thisgivesan application the necessarycontrol over the
Messaging Enabler. There are manyother preferencesof the Messaging
Enabler that can also be set in thisway.
Note that thisfunction isdesigned to be integrated with a single Newton
application and isideallysuited for vertical market applications. If two
separate Newton applicationswere to attempt thisoperation, the Messaging
Enabler preferenceswould be set to a combination of these two applications
and the resultswould be unpredictable.
Give me those In Box items!
So howdoesan installed Newton application get the itemsfrom the
Messaging Enabler once theyare in the In Box? Because the Messaging
Enabler isa transport, anyinstalled application can receive itemsfrom the
messaging enable using the standard Newton routing APIs.
Please refer to the Newton Programmers Guidefor a description of the
different mechanismsavailable for routing itemsfrom the In Box, specifically
RegInBoxApps, RegAppClasses, PutAway andAutoPutAway.
* And remember that the namesof the innocent have been changed to
protect the guilty.
Editing support; R. Robertson, J.C. Bell & A. Weiss.NTJ
Mock Entriesfor Debuggingby Bob Ebert, Newton Developer Technical Support.
Advanced Techniques
THEPROBLEM
The NSDebugToolspackage, part of NTK 1.6, allowsyou to set break
pointsin NewtonScript code. Thisisverypowerful and will help you find
manyof your bugswhich dont raise exceptions. However, once in a while
what you need to knowiswhen some object isaccessed, not when some line
of code isexecuted. One wayto do thisisto set the global variabletracetoTRUE, but then you typicallyhave to wait a long time for the trace output
to stop scrolling by, then wade through reamsof data to find the accessesyoure interested in.
MOCKENTRIESTOTHERESCUEA little-known and even lessfrequentlyused feature that wasadded to the
Newton OS in the 2.0release isthe abilityto create entry-like objects, called
Mock Entries. These objectsare composed of two parts. One part isa
simple NewtonScript frame, often called thecached entry. The other part is
ahandlerwhich knowshowto create and save the cached entry. The parts
together are sometimescalled afault block; when something needsthe
cached entryand it doesnt exist, afaultoccursand a message issent to the
handler, which then createsorfaults inthe entry.
The Newton OS in 2.0allowsyou to create these fault blocksfor your own
objects, which meansyou get to write the code that executeswhen the
cached object needsto be faulted in. The code that createsthe cached entry
can also do other things, for example it could enter a breakloop, which would
give you a chance to look at the stack and see whatsaccessing the frame.
Heresa simple example of using a fault block for debugging. Well create
a simple frame that printsan exclamation point in the inspector and beepsthe speaker everytime itsaccessed.
handler := {object: {foo: bar},EntryAccess: func(mockEntry)
beginwrite(!);GetRoot():Sysbeep();object;
end,};
f := NewMockEntry(handler, nil);
f isnowa Mock Entry. Hereshowit looksto the OS:
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
10/20
When anyslot inf needsto be accessed, the OS checksto see if there isa cached object. Because we passedNIL asthe 2nd argument toNewMockEntry, andEntrySetCachedObject hasnt beencalled, there will be no cached object forf. When there isno cached object,the OS callsthe handlersEntryAccessmethod, which isexpected tocreate the cached object, tell the OS about it using
EntrySetCachedObject, and return it.We cheat and dont callEntrySetCachedObject. The OS uses
the return value ofEntryAccess asthe object for thisaccess, and sincewe returnhandler.object everything works, but next timesomething touchesf, EntryAccesswill be called again. Theresourhookeverytime some part of the OS readsor writesanyslot inf,EntryAccess iscalled.
To almost all of the Newton OS,f lookslike a regular frame. f.fooevaluatestobar. ClassOf(f) isframe. f.baz := 42will add a slot to the frame, which isalso referenced as
handler.object in our example, so the next time the frame isaccessed, the modified object will be returned. The illusion iscomplete, only
the test functionIsMockEntry() can tell thatf isa mock entryand nota normal NewtonScript frame.
ANIMPROVEMENTIf you trythis, youll see that the frame isaccessed a lot more often than
you might think. Getting the value off.foo callsEntryAccesstwice. Setting a slot also callsEntryAccess twice. Creating a newslotcallsit 11times. Theprint function must do a lot, because printingf inthe inspector callstheEntryAccessmethod a whole bunch of times.
In our application debugging example above, we reallyonlywant to know
when the object isbeing used for the first time in a while. Recall that if the
OS findsthat a cached object exists, it wont callEntryAccess but willsimplyuse the object. So to prevent excessive calls, ourEntryAccessmethod will nowcreate the cached object. The trick then becomesclearing
the cached object. Ive found that clearing the object at a deferred time
workswelltypicallyitscleared the next time control returnsto the top
level, which issoon enough to catch most bugs. Hereshowto do that: ( the
bold text isnew)handler := {
object: {foo: bar},EntryAccess: func(mockEntry)
beginwrite(!);GetRoot():Sysbeep();EntrySetCachedObject(mockEntry, object);AddDeferredCall(
GetGlobalFn(EntrySetCachedObject),[mockEntry, nil]);
object;end,
};f := NewMockEntry(handler, nil);
You might want to experiment with clearing the cached object at other times.
LIMITATIONSTheEntryAccessmethod of the handler object iscalled onlywhen
a slot in the frame isaccessed. That is, a statement likeg := fwontcause theEntryAccessmethod to be called, since no slot inf isaccessed. The result of that statement will be that you nowhave two
referencesto the mock entryfault block, and eitherg.foo orf.foowill cause theEntryAccessmethod to be called.
The Newton 2.0OS onlysupportscreating mock objectsthat are backed
up byframes. While itsnot guaranteed, you might experiment and see what
happensif the object isan arrayor a binaryobject. (But back up your data
first!) Trysome special case binaryobjectslike stringsor real numbers.
Depending on your situation, you maybe able to use thisdebugging
technique with arraysor binaryobjectsaswell aswith frames.
Ive found that some partsof the OS work normallyin thiscasethe
mock object istreated just like a string, bitmap, array, or whatever. Other
partsof the OS notice that the object isa fault block and not the
appropriate object type, which typicallycausesa throw. The error messages
in thiscase can be interesting. For example, putting the stringfoo intheobject slot of thehandlerwill create an object that appearstobe a string. Printing works, but functionslikeStrLen(f) or theaccessorf[0] notice that the object isnt a string, and throwwith theseeminglycontradictoryerror message: Expected a string,got foo. Thishappensbecause the exception printerdoesntnoticethat the mock object isnt a string, and so it callsEntryAccess, getsthestring, and printsit.
ADVANCEDTECHNIQUESYou can put anyNewtonScript code in the handler, specificallyin the
EntryAccessmethod, so you can use thistrick to do other things. Forexample, you could add a counter and find out howmanytimesa frame is
accessed during some operation. You could add in a test to see if some slot
in the frame haschanged, and stop when it getsa certain value.
Unfortunately, when theEntryAccessmethod iscalled you donthave anyinformation about whatshappening. You cant tell if a slot isbeing
read or set. You cant tell which slot (or element, or byte) isbeing accessed.
If you write code that watchesfor changesyou end up finding out after the
change takesplace.
But thiscan still be useful. Consider if your handler settrace toTRUE and then set it toNILagain in a deferred call. Thiswould do a great
job of limiting the trace output to onlycode that actuallyused the object.
TheEntryAccessmethod might also watch for some change and,upon detecting the change, settrace toNIL and enter a breakloop.That wayyoud knowwithout doubt that the last section of trace output was
the one you needed to look at.You might even consider using mock objectsto implement a kind of
sentinel that letsyou knowwhen other applicationsaccessyour objects.
CONCLUSIONBeing able to have your code execute when a frame isaccessed is
powerful, and haslotsof good uses. However, keep in mind that any
observationsyou or I make about howthe OS dealswith mock objects
should be used onlyfor debugging. That is, it would be a mistake to write
production code that reliesonEntryAccess
October 1996 Newton Technology Journal
10
NTJ
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
11/20
Newton Technology Journal October 1996
11
#440F63D {_parent: {_parent: {#440D221},_proto: {#6008D0C1},viewCObject: 0x110926D,viewclipper: 17863292,base: ,viewFlags: 577,viewBounds: {#440F5C1}},_proto: {buttonClickScript:,text: Beep,viewBounds: {#6008D539},_proto: {@226}},viewCObject: 0x110A530,viewFlags: 515}
Now, letsget the parent slot and we will have the right view:
floatNGo := beepingButton._parent#440F5DD {_parent: {minute: 178,
downButton: {#440B2E9},calculator: {#4406159},mailEditor: {#44064C1},extrasDrawer: {#4409671},defaultTransport:Newton: {#4405DD9},OutOfMemoryAlert: {#4405D95},notification: {#4405D35},remindSlip: {#44060C5},namesButton: {#44063D9},folderEdit: {#4405DF1},phoneKeyboard: {#4405ECD},ovButton: {#440643D},upButton: {#4406461},thegang: {#44065F9},
printerSerialPicker: {#4405D05},...},_proto: {viewBounds: {#6008D199},
stepChildren: [#6008D1B9],_proto: {@180},debug: myFloatNGo,appSymbol: |Demo:NTK.Demo|},
viewCObject: 0x110926D,viewclipper: 17863292,base: ,viewFlags: 577,viewBounds:{left:-25, top:173, right:139, bottom:265}}
ThenumBeeps slot doesnt seem to be in thefloatNGo. The viewotherwise appearsto be correct. It soundslike a problem in declaring. Lets
check the Template Info dialog for that template (see Figure 3). Well, well,
well. Turnsout it actuallywasnt declared. Well checkmark the Declare To:checkbox and rebuild.
Figure 3: Template Info dialog showing undeclared numBeeps.
BEEPINGBUTTONBROUHAHA
Weve written a verysimple application in which the user can write a
number. Pressing the Beep button makesthe Newton beep that many
times. Figure 1showsthe application. Figure 2showsthe application
templatesin NTK.
Figure 1: Beeping Button application.
Figure 2: Structure of the Beeping Button project.
FIRSTPROBLEM
The first thing that happenswhen we write in a number and then press
the Beep button isa notification on the Newton: Sorry, a problem has
occurred (-48807). Letsturn onbreakOnThrows (clicking the icon inthe Inspector Window) and pressthe button again. Now, the Inspector prints
out
Undefined variable: numBeepsevt.ex.fr.intrp;type.ref.frame-48807
(#6008D1D1).buttonClickScript(), 3: Push text
Entering break loop: level 1
If we look at the code we see that were trying to accessthe
numBeeps variable from ourbuttonClickScript. That variableshould refer to ourprotolabelInputLine view. What could bewrong?If weve correctlydeclarednumBeeps to theprotoFloatNGo, theprotoFloatNGo viewshould have a slotnamednumBeeps. Letslook in that viewfornumBeeps. ( That viewisthe parent of our current self.) .First, letsgetself:
// get current selfbeepingButton := GetCurrentReceiver(0);
Debugging Tutorial: Finding & Fixing Bugsin an ApplicationJulie McKeehan and Neil Rhodes, Academic Press. 1996
Understanding NewtonScript
Excerpted from Programming for the Newton,2nd edition
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
12/20
SECONDPROBLEM(AHARDONE)We rebuild, download, and rerun. We write in a number and tap the
Beep checkbox. We get the following error in the Inspector:
Undefined variable: numBeepsevt.ex.fr.intrp;type.ref.frame-48807
(#6008D229).buttonClickScript(), 3: Push textEntering break loop: level 1
Thisisexactlythe same error at the same place we had it before. Letscheck
thefloatNGo viewagain:
beepingButton := GetCurrentReceiver(0);floatNGo := beepingButton._parentand here is what we find when the Inspector returns ourresult:#4412B0D {_parent: {minute: 181,
downButton: {#440B129},calculator: {#4406159},mailEditor: {#44064A1},extrasDrawer: {#4409651},defaultTransport:Newton: {#4405DD9},OutOfMemoryAlert: {#4405D95},notification: {#4405D35},remindSlip: {#44060C5},namesButton: {#44063D9},
folderEdit: {#4405DF1},phoneKeyboard: {#4405ECD},ovButton: {#440643D},upButton: {#440EF4D},thegang: {#44065D9},printerSerialPicker: {#4405D05},...},
_proto: {viewBounds: {#6008D1F1},stepChildren: [#6008D211],_proto: {@180},debug: myFloatNGo,numBeeps : NIL,stepAllocateContext: [#6008D731],appSymbol: |Demo:NTK.Demo|},
viewCObject: 0x1108C2C,numBeeps : {_parent: ,
_proto: {#6008D5D1},viewCObject: 0x1109F0C,entryLine: {#4419229},
labelLine: {#4418E49},width: 73,indent: 75,height: 13},
viewclipper: 17863746,base: ,viewFlags: 577}
ThenumBeeps slot seemsto be there and seemsto point to whatlookslike it could be our view. Letstryto accessit from the Inspector:
floatNGo.numBeeps#2 NIL
That doesnt make sense. We can see that it isthere. Letstryanother wayto
get to that viewusing theDebug function:
Debug(numBeeps)#2 NIL
Curiouser and curiouser. However, look verycloselyat the waythe
numBeeps slot printsout versusanyother slot:
_proto: {viewBounds: {#6008D1F1},stepChildren: [#6008D211],_proto: {@180},debug: myFloatNGo,numBeeps : NIL,stepAllocateContext: [#6008D731],appSymbol: |Demo:NTK.Demo|},
viewCObject: 0x1108C2C,
numBeeps : {_parent: ,_proto: {#6008D5D1},
Other slotshave no space before the colon (:), while thenumBeepsslot hasone space there. Could thishave anything to do with our problem?
What if that space were significant?LetstrycallingDebugwith an extraspace afternumBeeps:
Debug(numBeeps )
and here isthe Inspector return result that we get:
#4418AF5 {_parent: {_parent: {#4412B25},_proto: {#6008D0C1},viewCObject: 0x1108C2C,numBeeps : ,viewclipper: 17863746,base: ,viewFlags: 577},
_proto: {viewBounds: {#6008D681},label: Num Beeps:,entryFlags: 10753,_proto: {@189},debug: numBeeps ,preAllocatedContext: |numBeeps |},
viewCObject: 0x1109F0C,
entryLine: {_parent: ,_proto: {#356429},viewCObject: 0x110A83B,viewFlags: 10753,viewBounds: {#4418F4D},text: 2},
labelLine: {_parent: ,_proto: {#356569},viewCObject: 0x110A871,text: ?Num Beeps:,viewFont: {@100},viewBounds: {#4418E2D}},
width: 73,indent: 75,height: 13}
So if it actsasthough the name had an extra spacemaybe it does. Lets
check the Template Info dialog for that template more carefully(see Figure
4). Indeed, there isa trailing space afternumBeeps. Well delete it andrebuild.
Figure 4: Template Info dialog for numBeeps
with an extra space at the end.
THIRDPROBLEM
We rebuild, download, and rerun. We write the number 2 and tap
Beep. We get the following error in the Inspector:
Expected an integer, got nilevt.ex.fr.type;type.ref.frame-48406(#6008D229).buttonClickScript(), 27: PushConstant NILEntering break loop: level 1
October 1996 Newton Technology Journal
12
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
13/20
Newton Technology Journal October 1996
13
Were still in ourbuttonClickScript, about to execute the code atprogram counter 27. Heresthe NewtonScript code for the
buttonClickScript:
func()begin
local beeps := StringToNumber(numBeeps.text);for i := 1 to beeps do
:SysBeep();
end
Letslook at the disassembled code for the
buttonClickScript:
Disasm(GetCurrentFunction(0))0: FindVar numBeeps1: Push text2: GetPath 13: Push StringToNumber4: Call 15: SetVar beeps6: PushConstant 17: SetVar i8: GetVar beeps9: SetVar i|limit
10: PushConstant 1
11: SetVar i|incr12: GetVar i|incr13: GetVar i14: Branch 2317: PushSelf18: Push SysBeep19: Send 020: Pop21: GetVar i|incr22: IncrVar i23: GetVar i|limit24: BranchIfLoopNotDone 1727: PushConstant NIL28: Return
#2 NIL
Were about to execute the code at offset 27it looksasthough were at
the end of the loop. Letslook at the valuesof our variablesto see if theyare
reasonable:
GetAllNamedVars(0);#4419641 {beeps: NIL,
i: 1,i|limit: NIL,i|incr: 1,numBeeps: {_parent: {#4418345},
_proto: {#6008D5D9},viewCObject: 0x110A57D,entryLine: {#44186F5},labelLine: {#44181FD},width: 73,indent: 75,height: 13},
text: Beep,SysBeep: }
It doesnt seem right thatbeeps isnil. In fact, that would explain theerror we got. The for loop expected an integer, but got nil. But whyis
beeps nil?It wasobtained from callingStringToNumber onnumBeeps.text. Letsstart bylooking atnumBeepsmore closely:
numBeeps := GetNamedVar(0, numBeeps);#4417EA9 {_parent: {_parent: {#4411D11},
_proto: {#6008D0C1},viewCObject: 0x110A483,numBeeps: ,viewclipper: 17863765,base: ,viewFlags: 577},
_proto: {viewBounds: {#6008D689},
label: Num Beeps:,entryFlags: 10753,_proto: {@189},debug: numBeeps,preAllocatedContext: numBeeps},
viewCObject: 0x110A57D,entryLine: {_parent: ,
_proto: {#356429},viewCObject: 0x110A58C,viewFlags: 10753,
viewBounds: {#4418301},text: 2},labelLine: {_parent: ,
_proto: {#356569},viewCObject: 0x110A5C2,text: ?Num Beeps:,viewFont: {@100},viewBounds: {#44181E1}},
width: 73,indent: 75,height: 13}
Nowletslook at the value of thetext slot innumBeeps. Expectingto find the value of 2, we get a surprise instead:
numBeeps.text#4632AD
There isnt a text slot in thenumBeeps viewor template. So the valueofnumBeeps.text must be coming from theprotoLabelInputLine itself. Notice, however, that there doesseem to be atext slot with the value 2 innumBeeps.entryLine. But of course! For aprotoLabelInputLine, the input text isnt found in the text slot ofthe labelInputLine view, but in the text slot of the child viewwhere the input isactuallydone. With thisbit of fresh information we can
nowmodifythe code in the buttonClickScript. Our codeshould actuallybe:
func()begin
local beeps :=StringToNumber(numBeeps.entryLine.text);
for i := 1 to beeps do:SysBeep();
end
FOURTHPROBLEMWe rebuild, download, and rerun. We write in 2 in the input line and tap
the Beep button. We get the following error in the Inspector:
Expected an integer, got evt.ex.fr.type;type.ref.frame-48406(#6008D229).buttonClickScript(), 27: PushConstant NILEntering break loop: level 1
Hmm. Thisisthe same location where we broke before. Last time the
error wasExpected an integer, got nil. Thistimeit got a real number. Letstake a look atbeeps:
GetNamedVar(0, beeps);#4418E79 2.00000
Well, thatsthe problem. Thebeeps variable isa real number, not aninteger. Using our brilliant deductive capabilitieswe realize that
StringToNumbermust return a real number. Letscheck within theInspector:
continued on page 19
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
14/20
October 1996 Newton Technology Journal
14
Thisarticle isan excerpt fromNewton User Interface Guidelines,
published byAddison-Wesleyand summarizeswhat you should do to avoid
the top 20user interface mistakes. The book providesdetailed discussionsof
the correct approach you should use for each of the situationsdescribed here.
Info Button
Use the Info buttonwith the i iconand itspicker for information
optionssuch asHelp, About, and Prefs. Alwaysplace the Info button at the
far left end of the statusbar unlessyour application includesan Analog Clock,
which isoptional.
Newand ShowButtons
If userscan create newitemsor displaydifferent viewsof information in
your application, include a Newbutton and a Showbutton like the onesin
the built-in applications. Put the Newbutton near the left end of the status
bar next to the Info button ( if present) , and put the Showbutton to the right
of the Newbutton.
Screen Size
Design your application to handle anyscreen size and aspect ratio. If your
application cant scale itsviewssmall enough or cant rearrange viewcontents
to fit the aspect ratio, notifythe user before closing your application.
Tappingv. Writing
Tapping isfaster than writing, so for data input favor pickers, scrolling lists
and tables, radio buttons, sliders, and so forth over written input.
Picker Placement and Alignment
Align the top of a picker with the top of itsbutton or label. Make
exceptionsfor overviewpickers, for other verywide or verytall pickers, or for
small screens.
Displaya picker so itsbutton or label isat least partiallyvisible, and keep
the button or label highlighted while the picker isopen. (An overviewpicker
can cover the label or button that makesit appear.)
Field AlignmentBe consistent in howyou align field valueswith field labels( including
picker labels). Generallyyou should line up a fieldslabel with the fields
displayed value, not with the dotted line (if present) on which a user edits
the field value. In a viewthat hasseveral fieldsin a column, line up the labels
at their left edgesto insure a neat, orderlyappearance for your application.
Close Box Size
Use a regular (small) Close box in a viewwhere there are no adjacent
buttons. Use a large Close box onlywhere there are adjacent text buttonsor
standard-height picture buttons.
Button Location
Put buttonsthat affect an entire viewat the bottom of the view, and put
buttonsthat onlyaffect part of the viewelsewhere. Group buttonsthat
affect content and appearance at the bottom left of a view, and put buttons
that control or initiate action at the bottom right.
Button Spacing
Space adjacent buttonsthree pixelsapart, and leave four pixelsbetween
buttonsand the border of the viewtheyre in.
Button SizeMake everytext button 13pixelshigh and center the buttonsname
vertically. Make the button just wide enough that with the buttonsname
horizontallycentered there are three or four pixelsbetween the name and
the buttonsleft and right borders.
Capitalization
Capitalize the following itemslike sentences: check boxes, field
labels, and picker items. Capitalize the following itemslike book titles:
view titles, text button names, and radio buttons. In some contextsit
makessense to capitalize differently, but your should be consistent
within an application.
Picker Icons
Think twice before including iconsin pickers. Theyre hard to design and
have limited benefit.
Dismissinga Slip
If dismissing a slip doesnot cause an action to take place (other than
accepting changesmade to data in the slip), use a Close box for putting away
the slip. In thiscontext the Close box meansclose or put away. Use a
take-action button and a Close box if usershave a choice when dismissing
the slip of initiating an action or canceling. In thiscontext the Close box
meanscancel.
Take-Action ButtonName a slipstake-action button with a specificverb such asPrint, Fax,
or File. Onlyuse vaguelyaffirmative namessuch asOK and Yeswhere you
want to force usersto scan other partsof the slip to verifywhat action the
button initiates.
Fonts
Use fontscarefully. For the voice of the system and application use the
bold style of the System font in 9-or 10-point sizes. For valuesa user can
change use Casual 10-and 12-point. (Those are the fontsthat are preset by
the system protos.)
Avoiding Common UI Mistakes
Product Development
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
15/20
Newton Technology Journal October 1996
15
than 29pixelstall and wide. Leaving a little space helpsseparate icons.
Limit the length of an ExtrasDrawer iconsname to between 9and 11
charactersper line. Put a blank space in the name where you want it to break
and wrap onto another line.
Make a Newton icon more distinctive and easier to identifybygiving it a
distinctive silhouette rather than a boxyshape.
StorageAllowusersto move your applicationsdata between storage locations
with the Filing button in the ExtrasDrawersstatusbar. Thisisthe method
used bythe built-in applications.
Date and Time Input
To input datesand timesuse the speciallydesigned Newton pickers.
Keyboard Button
If your application includesa Keyboard button on the statusbar or at the
bottom of a slip, use the larger-size button (asin the Notepad) unlessspace
on the statusbar isconstrained (asin the Date Book) .
Punctuation to Avoid
Dont use ellipses(...) in button names, picker labels, or list-picker items.
Do put an ellipsisat the end of the title or the message text in a statusslip, but use three periodsrather than an ellipsischaracter. Also use an ellipsis
to accommodate an item whose text istoo long to fit on a line in the space
available for it ( for example, in overviews).
Dont use a colon at the end of a title, a heading, or a field label.
Extras Drawer Icons
To avoid overlapping iconsin the ExtrasDrawer, make yoursno more
Newton Connection Utilities1.0(NCU) isenabling technologythat will
integrate your Newton device with your existing WindowsPC or Macintosh
OS based computer. NCU will enable you to get connected with your favorite
desktop computer applications.
The featuresinclude Backup, Synchronize, Install, Import/Export and
Keyboard. The Backup function createsa backup file of your Newton PDA
and restoresinformation from that file to your Newton device whenever
necessary. The Synchronize function enablesdirect exchange of information
between popular desktop applicationsand your Newton PDA. The Install
Package function enablesthe installation of Newton software onto your
Newton PDA. The Import function enablesthe sending of information from
PIMs, word processors, or text filesinto your Newton PDA. The Export
function enablesthe sending of information from your Newton PDA to your
personal computer in a varietyof formats, including word processing and PIMformats. The Keyboard function enablesusage of your PC keyboard to enter
information directlyinto your Newton PDA.
Integrate the Newton with the following applicationsusing NCU:
Mac OS based computer:
NowUp To Date 3.0/3.5
NowContact 3.0/3.5
NowDateBook 4.01
NowTouchBase 4.01
ClarisOrganizer 1.0
RTF
Delimited ASCII
Windows PC:
Schedule+ 7.0
Ecco 3.03
LotusOrganizer 2.1
SideKick95
Sidekick for Windows1.0
Sidekick for Windows2.0
Delimited ASCII
Word 2.0/6.0/7.0
NTJ
Get Connected!
Newton Directions
Newton Connection Utilities 1.0 Beta
this Summer,Shipping this Fall.
by Cami Hsu, Apple Computer, Inc.
NTJ
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
16/20
October 1996 Newton Technology Journal
16
The High Level Frame Desktop Integration Library(HLFDIL) isused to
move Newton framesand arraysto and from a desktop machine, running
either the Macintosh OS or Windows. (In common usage, HLFDIL isusually
shortened to Frame Desktop Integration Library, or FDIL, and the two terms
are used interchangeablythroughout thisarticle.) Before the HLFDIL can be
opened a connection between the Newton and the desktop machine must
be established using the CommunicationsDesktop Integration Library
(CDIL).
The FDIL isused to map the dynamicstructure of Newton framesto the
staticstructuresused on desktop machines. Aswith the CDIL, it is
implemented in C+ + but hasa C language API. The basicassumption of
the FDIL isthat the format of the Newton framesbeing moved isalready
known. A C language structure having a one-to-one correspondence with the
Newton frame can be defined, and the desktop programmer can define the
mapping of slotsto fields. However, since there are caseswhen the
programmer maynot knowthe structure of the Newton frame in advance or
when additional slotshave been added to the frame, there must be a wayto
handle these unexpected or unknown slots. Thisishandled bythe FDIL by
uploading these slotsasunbound data, that is, data for which there isnot a
previouslydefined memorylocation of the appropriate size and type. The
unbound data istherefore put into memoryon the desktop machine in a
tree structure which defineswhere the data isin the NewtonScript frame in
relation to other slotsin the frame.
Throughout thisarticle, the use of the FDIL to transfer Newton frame data
will be discussed. However, it should be remembered that it isalso used to
transfer Newton arraydata. It isworth noting that the FDIL cannot be used to
transfer simple data such asintegersor stringsunlesstheyare part of a frame
or array. It isrecommended that such data be transferred using the CDIL
mechanism, or put into a simple NewtonScript frame, such as
fooFrame:={myInteger:3}.
Openingthe FDIL and CreatingObjects
After the CDIL connection, or pipe, hasbeen opened, the FDIL maybe
initialized and used. The FDIL routine FDInitFDIL iscalled asfollows:
fErr = FDInitFDIL();
Anyerror in initializing the librarywill be returned. FDIL errorsfall in the -
28000range and a complete list maybe found at the end of the FDIL section
of the documentNewton Desktop Integration Librarieswhich can be found
on the DIL web page at http://dev.info.apple.com/newton/tools/dils.html.
Next, one or more FDIL objectsmust be created using the routine
FDILCreateObject which isdefined as:
DILObj *FDCreateObject(short objType,char *objClass);
The first argument describeswhether the object being created isan array
or a frame, and the second argument isan optional classname which
NewtonScript arraysmaycarry. Each frame or arraywhich istransferred must
have a separate object created for it. Thisincludessub-framesand sub-arrays
within a parent frame or array.
For example, for the following NewtonScript frame, three separate FDIL
objectsmust be created before the frame can be defined on the desktop:
aFrame:={name:foo,phone:[333-444-5555,101-202-3333],address:{street:123 Main, town:Fooburg,state:GA, postalCode:12345}
}
There must be an FDIL object for the main frame,aFrame, one for thephone sub-arrayand one for theaddress sub-frame.
The callsto create these FDIL objectswould look like this:
DILObj *aFrameObj, foneObj, addrObj;
aFrameObj = FDCreateObject(kDILFrame, NULL);foneObj = FDCreateObject(kDILArray,homePhone);addrObj = FDCreateObject(kDILFrame, NULL);
In thisexampleFDCreateObject iscalled twice with thepredefined constantkDILFrame to create an object for defining a frameand once to create an arrayobject using the
kDILArrayconstant for the
first argument. In the case of the array, we also supplythe classname
homePhone asit isa named (classed) array. Named arraysaredescribed on page 2-9of theNewtonScript Reference. (An electronicversion
of thisbook isavailable from the Newton documentation web page noted
above.)
Asof thiswriting a known bug existswhich will throwan error on the
Newton when a string isdownloaded, if an arrayincludesan unnamed string
(that is, a classlessstring) asone of itselements. The work around isexplicitly
to give unclassed stringsthe default classof string when theyare array
members. See the routineDearchiveFrame in the FDIL Archive Labsolution code for an example of thiswork around. Thisbug should be fixed
in future releasesof the HLFDIL.
DefiningObjects
Once you have created an FDIL object, you maybegin to bind memory
locationsto the object. Thisprocessdescribesto the FDIL where data being
transferred to or from the Newton will come from or go to. In other words,
bybinding a memorylocation on the desktop to a slot in a Newton frame,
the FDIL knowswhere to put data or where to go to get data. The memory
locationsused in thisbinding maybe a variable on the stack, a global
memorylocation or a dynamicallyallocated heap location, depending on the
use and duration of the data being transferred.
The routineFDbindSlot isused to connect the memorylocation
The High Level Frame Desktop Integration Library(HLFDIL)by Bill Worzel, Newton Developer Training
Communications Technology
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
17/20
Newton Technology Journal October 1996
17
with the Newton slot. Itsformal definition is:
objErr FDbindSlot(DILObj *theObj,char* slotName,void *bindVar, short varType, longmaxLen,long curLen, char *objClass);
The first argument (theObj) isthe object created to define the framebeing transferred, and the second (slotName) isthe name of the slot
that isbeing bound.The third (bindVar) isa pointer to the memorylocation to which the
slot isbeing connected. When data isto be downloaded to the Newton this
will be the location of the data being sent. In the case of an upload from the
Newton thisisthe place where the received data will be put. In the latter case
it isup to the programmer to make sure there isenough room to hold the
data being received. ThemaxLen argument givesthe total size of theobjectsbuffer, and thecurLen argument tellshowmuch of that bufferhasbeen filled byyour desktop application (that is,maxLen isused forreceiving data from the Newton device, andcurLen isused for sending it) .In the case of an arrayor frame,maxLen andcurLen should be set to -1.
ThevarType argument describeswhat type of data object the slotbeing bound isexpected to be. The following table showsthe existing types:
kDILPlainArray // as opposed to a classed arraykDILArray // array with class name associatedkDILBoolean // true or falsekDILUnicodeCharacter // 16-bit characterkDILCharacter // 8-bit ASCIIkDILFrame // object is a framekDILSmallRect // packs a Newton rect into a longkDILImmediate // Newton immediate value (not int)kDILInteger // 30-bit integerkDILNIL // Newton nil value (NULL)kDILBinaryObject // double or other binary sequencekDILString // char *kDILSymbol // handled as char *
Of these typesseveral are worth special mention.
kDILArrayversus
kDILPlainArray-manyarrayson the
Newton are simplysequencesof data but a fewhave a classassociated with
them.kDILPlainArray hasno classassociated with it whilekDILArray does.kDILBoolean andkDILNIL -both have platform-specific
definitionsfor the valuestrue, false and nil.
kDILSmallRect isautomaticallyused when a frame on theNewton which isused to store a rectangle issent and the rectangle values
(top, left, bottom, right) all fit in a single byte value. In thiscase the valuesare
packed into a single long value.
kDILBinaryObject isused for anyunspecified binaryobject(such assounds, pictures, and so forth) aswell asfor the Newton Real type.
Note, however, that unlike integersor immediates, platform-specificbyte
ordering must be accounted for.Make sure you compile using 8-byte doublesif you are going to transfer
Real numbers. When transferring Newton Real numbers, you must set your
development environment to use 8-byte double valuesor it will interpret the
realsreceived asa different value than expected. Thisisusuallyan option
specificto your system. For example, Metrowerksdefaultsto 4-byte doubles
and the 8-byte double option must be specified in the compiler optionsin
the Preferencesmenu item. MPWdefaultsto 8-byte doublesand so no special
action must be taken.
kDILString includesboth classed and unclassed strings.kDILSymbol isa Newton symbol (such asmySymbol) transferred to
and from the desktop asa C string.
The last argument inFDbindSlot (objClass) isthe class, ifany, of the object. While manyobjectson the Newton have no class
associated with them, manymayhave a classassigned bythe programmer or
bythe system. For example, while most stringshave no classassociated with
them, theymayhave one assigned explicitlybythe Newton programmer.
Conversely, Newton Real numbersalwaysare transferred asobjectsof type
kDILBinaryObject with a classof Real. If an object hasnospecial classassociated with it, thisargument should be a NULL to use the
default classsymbol (string, array, etc ). If it hasa classit istransferred
with a C string, such asfor the classname.
An example taken from the SoupDrink sample code involvesdownloading
a name frame to the Newton Name soup. The following pseudo-
NewtonScript describesa card frame and itsassociated FDIL type:
card := {
cardType:kDILInteger,Name: kDILFrame,Address: kDILString,City: kDILString,Region: kDILString,Postal_Code: kDILString,
phones: kDILArray,sorton: kDILString}
Thisisonlya code fragment from the SoupDrink example. The variables
shown (such asthe name strings) are assigned valuesin earlier code. To see
the full code, see the SoupDrink code walk through.
In the same waytheName frame and thephones arraymaybedefined as:
Name := {
class: kDILSymbol,first: kDILString,last: kDILString
}
phones := [kDILString, kDILString, ...]
While not shown here, the elementsof thephones arrayeach have aseparate classassociated with them such asHomePhone, WorkPhone,
and so forth.
The code to create the FDIL object for thisstructure is:
name = FDCreateObject(kDILFrame, NULL);FDbindSlot(name, Class, (void *)&pClass, kDILSymbol,
strlen(pClass), -1, NULL);FDbindSlot(name, first, (void *)&fName, kDILString,
strlen(fName), -1, NULL);FDbindSlot(name, last, (void *)&lName, kDILString,
strlen(lName), -1, NULL);
phones = FDCreateObject(kDILArray, NULL);FDbindSlot(phones, NULL, (void *)&phoneNo, kDILString,
strlen(phoneNo), -1, HomePhone));
entry = FDCreateObject(kDILFrame, NULL);FDbindSlot(entry, cardType, (void *)&cardType,kDILInteger, sizeof(int), -1, NULL) ;FDbindSlot(entry, Name, (void *)name, kDILFrame, 0, -1,
NULL);FDbindSlot(entry, Address, (void *)&addr, kDILString,
strlen(addr), -1, NULL) ;FDbindSlot(entry, City, (void *)&town, kDILString,
strlen(town), -1, NULL) ;FDbindSlot(entry, Region, (void *)&state, kDILString,
strlen(state), -1, NULL) ;FDbindSlot(entry, Postal_Code, (void *)&zip,kDILString, strlen(zip), -1, NULL) ;
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
18/20
FDbindSlot(entry, phones, (void *)phones, kDILArray, 0,-1, NULL) ;
FDbindSlot(entry, sorton, (void *)&sName, kDILString,strlen(sName), 0, Name);
Here the FDIL objectsname andphones are bound to slotsin theentryobject. Note also that the string in thephones arrayhasa classassociated with it, HomePhone. Once theentry object isdefined it is
readyto be used to download it to the Newton.
TransferringData
Once an FDIL object iscreated and the slotsare defined bybinding them
to desktop memory, it maybe used to transfer data to or from the Newton.
Thisisdone byusing the routinesFDget to upload and FDput to download
the object and itsassociated data. These routinesare defined as:
objErr FDput (DILObj *entry, short type, CDILPipe *pipe);
objErr FDget (DILObj *entry, short type, CDILPipe *pipe,long timeOut, CDILPipeCompletionProcPtrcallBack,long refCon);
Notice that the CDIL pipe isused here since thisisthe first time that data
will actuallybe transferred. Note also that the FDget routine maybe called
asynchronouslybypassing a procedure pointer in for the fifth argument.
In both routinesthe first argument (entry) isthe master object beingtransferred. It mayhave sub-framesand arraysobjectsbound to it but thisis
the top level object. The next argument (type) isthe FDIL type(kDILFrame orkDILArray) of thismaster object. The thirdargument (pipe) isthe CDIL pipe being used to transfer the data.
For FDget we have these additional arguments:
The fourth argument (timeOut) defineshowlong the FDIL shouldattempt to transfer the object before giving up and returning an error. The
timeout value ismeasured in millisecondson Windowsmachinesand ticks
on Macintosh OS machines.
The next argument (callBack
) isa pointer to a callback routine if
the FDget call ismade asynchronously. If you are making the call
synchronously, simplypassNULL for thisargument.
The last argument (refCon) isan arbitraryvalue which can be passedto your completion routine.
SoupDrink downloadsthe previouslydefined entryFDIL object to the
Newton using thiscall toFDput:
FDput(entry, kDILFrame, ourPipe);
The Newton must be in a state to receive a frame or arraybefore it issent
from the desktop machine. See the SoupDrink code for the Newton for an
example of code which importsand exportsframes.
Unbound DataUnbound data isdata which arrivesat the desktop but isnot bound to
anymemorylocationsbycallstoFDbindSlot(). Thistypicallyoccursin two situations: when the desktop programmer doesnot knowthe
structure of the Newton data beforehand and when there are previously
unknown slotswhich have been added to a frame.
An example of the first case isa program which allowsthe programmer to
select what will be transferred. SoupDrink doesthiswhen it allowsthe
programmer to name a Newton soup which isto be uploaded. In thiscase
SoupDrink providesa universal wayto handle all soupsbyuploading the
information asunbound data which it then writesto file.
The second situation occurseither when there isa system or program
update or when applicationswhich tag along on system soupsare added.
For example, if a newversion of the Namesapplication added newslotsto
the soup framesstored for a Name card, SoupDrink would get the data from
the old slotsif it used the entrydefinition shown above but would not have a
place allocated to put newdata slots. Similarly, if a newcontact application
wasloaded into the Newton, it might choose to build off of the existing
Namesapplication but add additional information to the soup entries. In thiscase SoupDrink would get the standard data but would not be prepared for
the data added to the Namessoup entries.
In either case, unbound data providesa wayto accept unknown data slots
and then to parse them for further disposition. Following isa description of
unbound data and howto extract information about the data once it has
arrived at the desktop.
Unbound data islinked together in a chain of data structuresof type
slotDefinition. TheslotDefinition data type isdefinedasfollows:
typedef struct slotDefinition{short varType; // Data type of this variable
void *var; // Actual pointer to dataulong length; // Length of data (strings)ulong maxLength; // Maximum Length of dataulong streamLen; // internalulong bufIndex; // internallong namePrec; // internallong classPrec; // internalchar *slotName; // Name of slot for this varchar *oClass; // class of this objectshort slotType; // Data type of this slotulong truncSize; // Current size of truncated objectlong childCnt; // Number of child nodeslong peerCnt; // Number of peer nodesshort dataFilled; // TRUE if data added in this oplong internalFlags; // Internal state flagsshort boundData; // internalstruct slotDefinition *children;struct slotDefinition *next;} slotDefinition ;
The fieldswhich are significant to understanding the structure of
unbound data are thechildCnt, peerCnt, childrenandnext fields. Unbound data isstored asa seriesof linkedslotDefinition structureswhich mayhave siblings(peers) orchildren. In thisscheme,peerCnt isthe number of peersan item has,childCnt isthe number of children,next isa pointer to theslotDefinition for the next peer in the list andchildren isapointer to the start of the chain ofslotDefinitions for thechildren of the item.
Thisisshown in the following diagram:
October 1996 Newton Technology Journal
18
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
19/20
-
7/28/2019 Newton Technology Journal: Volume 2, Number 5
20/20