Genii Weblog

Re-inventing the wheel

Thu 13 Nov 2003, 10:02 AM

by Ben Langhinrichs
Well, our @Midas Formulas beta has had its fits and starts, mostly because the feedback I have gotten, and the impression I have myself, is that the syntax is too difficult.  It is difficult to take a set of classes that were specifically designed for LotusScript and re-invent them for a different language with different expectations.  While I have seen fairly spectacular formulas written in the formula language, the sort of code the Rocky Oliver excels at, the general expectation is that a very short concise set of lines of formula language should suffice for most situations.  

In LotusScript, for almost any script, there is a sequence of code fragments:
  1. Turn on Option Declare (if it is not already there by default in Notes 6+)
  2. Include any LSX or script libraries
  3. Dimension the variables
  4. Set up the initial database/collection/document
  5. Traverse the collection/items/whatever
  6. Do the action
  7. Close out whatever needs to be closed out.

Due to all this, it is unusual to have a LotusScript script that is fewer than fifty lines or so (see this post for a fairly minimalist script, and it still takes almost twenty lines of code).

Formula Language
Formula language is different.  Many formulas for computed text or column formulas are only a single line or perhaps two, even if a series of events take place.  Take for example, the following:

res := @DbColumn(""; @DbName; "Products"; "2");
@If(@IsError(res); "Error: " + @Text(res); @Implode(@Unique(@Trim(res))));

Two lines, and we look up a column of values, check for errors, remove duplicates, trim spaces and consolidate into a string separated by semi-colons.  Try to write the same code in LotusScript in under fifty lines.

@Midas Formulas - Beta One
OK, here is the confession.  My thinking about @Midas Formulas has been guided too much by the description of the product as a "formula language version of Midas".  While I worked hard to make the commands concise, I still managed to write "LotusScript in Formula language", which is counter-intuitive and awkward.  There were exceptions.  The @DbColumn and @DbLookup examples were fairly well constructed and clear.  The following line

prices := @DbColumn("Midas"; @DbName; @DocumentUniqueID; "Body"; 2; "Format='Currency' SkipTitle='Yes' ");

would access the Body field of the current document,  and return the second column of values in the first table as a numeric list.  The assumed format would be currency, so if the table was that below, the return value would be 595:750:350.

IBM Value Package for Developers
Annual fee
North America, Europe, Middle East, Africa 
Latin America 
Asia Pacific region

So far, so good.  Rich text accessible as data, and fairly simply.  Unfortunately, doing other things started exhibiting signs of "LotusScript in formula language".  There were two variations.  The first was the "run on sentence" variety, such as:

@DbCommand("Midas"; "ConnectPage"; ""; "Resources"; "GenerateHTML"; "Table " + @Text(count); "XHTML"; "Generation='Fragment'")


@DbCommand("Midas":"NoCache"; @DocumentUniqueID; "Body"; "RemoveLinks"; @True; "LinkMatching"; "":"MedXref.nsf"; "MedLinks"; "Term"; "Link"; ""; "Save")

Where does one command stop and the next begin? This syntax allowed a series of commands to be put together, as a fairly crude way to shorten the formulas, but even I could never figure out how to handle methods that had optional parameters, and you had to be very, very careful to assure that the final parameter for one was not confused with the function name for the next.

The second variation of "LotusScript in formula language" was actually not quite as bad, even though it looks even more like LotusScript coding.  This is the script conversion variation, such as:

@DbCommand("Midas":"NoCache"; "Connect"; @DocumentUniqueID; "Body");
@DbCommand("Midas":"NoCache"; "DefineChunk"; "Table *; Row 1");
@DbCommand("Midas":"NoCache"; "Font"; "Blue 12pt Bold");
@DbCommand("Midas":"NoCache"; "Save"; "SaveOnlyIfModified='Yes'");

This at least makes sense, although it is a bit verbose.  It is easy to read if you already know the Midas Rich Text LSX.  Connect to the rich text field, define a chunk, set the font and then save.  Only problem is, this is the simplest possible formula to do nothing but set the font, and the more you do, the longer it gets. 

@Midas Formulas - Beta Two
So, how do we make this more "formula language" and less "LotusScript"?  The first step is to look at what works well.  The @DbColumn function works because everyone is familiar with the basic syntax.  First you have your database, which can be shortened to "" for the current database.  Next, you drill down, in this case to the document instead of the view.  Next, you drill down to the specific rich text field.  Finally, you specify which column to return.  The extension of the properties at the end and the use of  rich text table instead of a view are pretty easy transformations.

So, lets take the same approach for the @DbCommand, which is less familiar.  The general syntax will be:

@DbCommand("Midas":"NoCache"; cmd-name;  db-selection;  note-selection; field[:chunk]; cmd-args)

where db-selection could be "" or @DbName or "Aladdin/Genii":"showcase.nsf" or anything of that nature, and note-selection can be the special function @DocumentUniqueID or the note-id of a document or the universal id of a document or a design element type and name such as "Form":"Example Form".  The same basic syntax will apply to @DbColumn and @DbLookup, as

@DbColumn("Midas":"NoCache"; db-selection;  note-selection; field[:chunk]; column)
@DbLookup("Midas":"NoCache"; db-selection;  note-selection; field[:chunk]; key; column)

In addition to this syntactical simplification, lets 

  • expand the number of commands to incorporate certain parameters, such as using GenerateXHTML rather than using GenerateHTML and passing a parameter to identify that it should be XHTML.
  • get smarter about using appropriate defaults, so we do not have to pass in properties which could have been assumed.  If I am generating XHTML for a specific chunk as in this case, it is more likely to be  a fragment, so that should be assumed
  • assume that commands which modify a rich text field will save automatically, and ones which do not modify the rich text will not save.  In the case where the counter-intuitive happens, use the equivalent of a [modifier] on the command, so that "ChangeFont" would save automatically unless you made the command "ChangeFont":"[NoSave]"

Using these changes, the original

@DbCommand("Midas"; "ConnectPage"; ""; "Resources"; "GenerateHTML"; "Table " + @Text(count); "XHTML"; "Generation='Fragment'")

becomes in beta two

@DbCommand("Midas"; "GenerateXHTML";  "";  "Page":"Resources"; "":"Table " + @Text(count))

and the original

@DbCommand("Midas":"NoCache"; @DocumentUniqueID; "Body"; "RemoveLinks"; @True; "LinkMatching"; "":"MedXref.nsf"; "MedLinks"; "Term"; "Link"; ""; "Save")

becomes in beta two

@DbCommand("Midas":"NoCache"; "RemoveLinks"; ""; @DocumentUniqueID; "Body"; @True)
@DbCommand("Midas":"NoCache"; "LinkMatching"; ""; @DocumentUniqueID; "Body"; "":"MedXref.nsf"; "MedLinks"; "Term"; "Link")

and the original

@DbCommand("Midas":"NoCache"; "Connect"; @DocumentUniqueID; "Body");
@DbCommand("Midas":"NoCache"; "DefineChunk"; "Table *; Row 1");
@DbCommand("Midas":"NoCache"; "Font"; "Blue 12pt Bold");
@DbCommand("Midas":"NoCache"; "Save"; "SaveOnlyIfModified='Yes'");

becomes in beta two

@DbCommand("Midas":"NoCache"; "Font"; ""; @DocumentUniqueID; "Body":"Table *; Row 1"; "Blue 12pt Bold");

with the save happening automatically if any changes have been made.

There is a reason why we have beta versions, and clearly we have made some strides toward making @Midas Formulas more usable.  The actual beta two should be sent out later today or early tomorrow, and we'll see what the beta testers think.  If you would like to be a beta tester, please do sign up.

Copyright 2003 Genii Software Ltd.

What has been said:

No documents found