A deeply ingrained habit of mine is using ampersand to concatenate strings in LotusScript (when I'm not bypassing operators entirely, such as using NotesStream or StringBuffer to optimize massive concatenations) - so deeply ingrained that when NTF asked me today why I don't use plus instead, for a moment I couldn't remember my original reason for switching... but after mulling it over briefly I remembered that I hate type coercion with a passion. It bugs me because it tries to be too smart and often fails. Just like extended syntax. For example:
"100" + "200" = "100200" This may seem obvious: we're concatenating 2 strings, so it takes the value of one and appends the other. But... 100 + "200" = 300 The LotusScript interpreter decides that, since it's starting with a numeric value, you're obviously trying to add another numeric value. Since in this case the string can be converted to a number, it does so and adds the operands instead of concatenating them as strings. So, logically: "100" + "200" = ...300? That's right: plus is primarily an addition operator, so if there's any possible way it can remain one, it will. In fact: 100 + "two hundred" = type mismatch - at compile time if it knows the latter is a string, at runtime if it's a variant... reason #372 why variants should be used sparingly and with caution. Speaking of which, I think it was Nathan who once told me, "Variant should have been called Deviant... 'cause it'll accept any object". Yeah, I know, ew. But you gotta admit, that's darned funny.
So how did he convince me plus is better than ampersand despite my pedantic aversion to coercion?
- (Author's note: this was actually a third realization, which came after the discussion.) In LotusScript string concatenation, some coercion is unavoidable. Since ampersand's only valid use is as a concatenation operator, any scalar entering the operation is treated as a string whether you wanted it to be or not. So unless everything's a string to begin with, it's coercing anyway, it's just safer. But if we're subscribing to a "flexible input, strict output" philosophy, we're already making sure we know what data type we're dealing with and handling it appropriately, so ampersand doesn't really gain us much... it's only when we're being lazy about this that ampersand saves us from returning unexpected results.
- Whenever possible, it's helpful to use conventions that are optional in one language but required in another. In Formula, but - more importantly, over the long haul - also in JavaScript and Java, we don't have a choice: we have to concatenate with plus; might as well do it in LotusScript too so that we're spending more time thinking about how to implement the actual functionality at hand and less time trying to remember what operators to use in the current language... same reason I always surround my conditional expressions in parentheses: I know LotusScript doesn't force me to, but JavaScript and Java do, so why erode a good habit just because LotusScript would allow me to be lazier than that?
- In XML, an ampersand must be entity-encoded; a plus can be left alone. This was the "you had me at hello" argument. For the foreseeable future, any convention that allows my code to be handled more easily within an XML context is likely to appeal to me, even if it forces me to abandon a long-held alternate approach.
Anything you can think of that I'm overlooking? If not, I'm switching to plus effective immediately. That is, as soon as I get back to writing LotusScript... it's been nothin' but Java for me all week.
|
I was wrong: plus is better than ampersand
|
This entry is related, but varies slightly from, Bob Balfe's article on debugging Eclipse plugins in Notes 8. My current hobby project is written entirely in Java, but it's not an Eclipse plugin - at least, not yet... once the application's API is finalized, the code I'm writing now will find its way into a plugin, a web service, a server-side JavaScript library for use in one or more XPages, and so on. But before I get carried away with any of that, I first need to get the core functions working.
I'm still primarily a LotusScript developer, so I'm accustomed to relying heavily on the LotusScript debugger to tell me why my code isn't behaving precisely the way I'd imagined it in my dreams... just kidding, I don't dream in LotusScript. Okay, there was that one time, but trust me... you don't want me to tell that story. Anyway, I've long since adjusted to adding semicolons at the end of each line, curly braces to open and close conditional blocks, and the like... JavaScript's optional preference for same has, over the course of several years, gradually prepared me for Java's non-negotiable stance on such things. But not having as informative of a debugger was really starting to bug me (rimshot). Besides, my testing process had grown rather cumbersome:
- Write the code in Eclipse (so I can actually get typeahead on both imported and custom classes, and easily integrate with SVN - not only so I can roll back to a previous version if I completely mangle something, but also to take advantage of Nathan's frequent midnight mindstorms).
- Export to a JAR.
- Open the test agent in Designer.
- Delete the JAR from the project and save it (since there's no "refresh" option to force the design element to notice that the local file has changed... I was going to write a separate agent to recreate the test agent using DXL by Base64-encoding the JAR and... yeah, ew.), wait for Designer to squawk at me that it could no longer compile, click Yes to save it anyway, add the JAR back in, save again.
- Run the agent.
- Check the three databases that should have new / modified documents if the code worked, and verify that all items were written correctly.
- Open / switch to the Java Debug Console to sift through ridiculously verbose logging and stack traces for some hint of why one item value had been set incorrectly.
- Return to step 1, hopefully now aware of which precise line of code needs to be updated - and how - in order to fix the bug. Repeat as long as necessary.
As my friend Sean Kelly would put it, "pain... you know it isn't easy". Here's my new process:
- Write the code in Eclipse.
- Open the class file that defines the unit test I want to run.
- Click the cute little bug icon in the Eclipse toolbar to launch debugger, then step into and over until it crashes or completes.
- Generally speaking, at this point I don't even need to switch back to Notes, because if it didn't work, I saw it go wrong during the debug run, so I know exactly where to look, even if I wasn't logging a durned thing. Return to step 1, repeat as long as necessary.
What changed? Surprisingly little:
- I had to add the Notes program file ( on this laptop, that's just "C:\Notes" ) to the PATH system environment variable. And, though I didn't realize this until later, I had to reboot for that to take effect.
- While normally I'd just include a standard JRE in my project build path, I changed this project's build path to point to an "alternate JRE": namely, the one included in Notes 8. To specify the Notes JRE as an alternate in Eclipse, select Window > Preferences, then navigate to Java > Installed JREs. Click Add, choose "Standard VM" as the type ( and click Next ), then give it a name ( like "Notes 8" ), and set the JRE home to "[Notes Program Folder]\framework\rcp\eclipse\plugins\[OS-specific folder]\jre", then click Finish. In my case, the [OS-specific folder] is "com.ibm.rcp.j2se.win32.x86_1.6.0.20080709-200808010926".
- Here's the crucial part: the class has to be runnable, so it needs to be treated like a command-line Java class - namely, it needs a static void "main" method - and it needs to start and stop a Notes thread ( I'd also recommend syncing your Notes and OS passwords so that you can skip being prompted for your password when the thread is started ).
For example:
public static void main(String[] args) {
NotesThread.sinitThread();
NotesThread.stermThread();
} That's all it takes. I now have a class for each of my unit tests. So I have one that creates a document, another that formats a summary of a document collection as JSON, and so on. Whenever I make any code changes, I run the unit tests for verifying any functionality that is impacted by the change I just made... so, without ever leaving Eclipse, I know right away whether or not I've just mangled something... and if so, what needs to change.
|
Debugging Notes and Domino Java code in Eclipse
|