Ben Langhinrichs

Photograph of Ben Langhinrichs

E-mail address - Ben Langhinrichs







Recent posts

Thu 10 Jun 2021

Notes 12 without all the blue



Wed 5 May 2021

Pull public data into Notes on the fly



Thu 29 Apr 2021

Archive a Notes DB off-line w/ Field data and active content


August, 2021
SMTWTFS
01 02 03 04 05 06 07
08 09 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

Search the weblog





























Genii Weblog

Simplifying hard to read formulas

Thu 11 Nov 2004, 03:19 PM



by Ben Langhinrichs
In working with @Midas Formulas, I am reminded as I have not been for a while how convoluted complex formulas can look.  The formatting is not simple, and the formulas tend to look like badly run on sentences.  In any case, here are three tips on how to make a complex formula a bit more readable.

I will start with a gnarly example from my unreleased Hide-When 1.0 sample database showing how the Midas Rich Text LSX and @Midas Formulas can work with hide-when formulas.  I have a nasty sort of agent which prompts for one of a selected set of criteria and then loops through setting hide-when flags on any paragraph which matches.

Original formula code
choice := @Prompt([OkCancelList]; "Select criteria"; "Select which paragraphs to hide from read mode:"; "1) Those which do not start with D"; "1) Those which do not start with D":"2) Those with images":"3) Those with the substring 'Raven' in them");
p := 1;
t := @DbCommand("Midas":"NoCache"; "GetCount"; @DocumentUniqueID; "Body"; "Paragraph");
@For(p:=1; p <= t; p := p+1;
   @If(@Begins(choice; "1"); 
              @If(!@Begins(@DbCommand("Midas":"NoCache"; "Text"; @DocumentUniqueID; "Body":("Paragraph "+@Text(p))); "D");
               @DbCommand("Midas":"NoCache"; "ParagraphStyle"; @DocumentUniqueID; "Body":("Paragraph "+@Text(p)); "+HIDE_READ +HIDE_PREVIEW_Read"); "");
          @Begins(choice; "2"); 
              @If(@DbCommand("Midas":"NoCache"; "GetCount"; @DocumentUniqueID; "Body":("Paragraph "+@Text(p)); "Graphic") > 0;
               @DbCommand("Midas":"NoCache"; "ParagraphStyle"; @DocumentUniqueID; "Body":("Paragraph "+@Text(p)); "+HIDE_READ +HIDE_PREVIEW_Read"); "");
          @Begins(choice; "3"); 
              @If(@Contains(@DbCommand("Midas":"NoCache"; "UnformattedText"; @DocumentUniqueID; "Body":("Paragraph "+@Text(p))); "Raven");
               @DbCommand("Midas":"NoCache"; "ParagraphStyle"; @DocumentUniqueID; "Body":("Paragraph "+@Text(p)); "+HIDE_READ +HIDE_PREVIEW_Read"); "");
""));
SELECT @All

Tip 1: Use local variables to replace lists, strings or other "constants"

These five steps are all variations on this tip, taken to simplify and shorten the formula.

1) Make the list of choices into variable 'c', which allows us to use c[1] in the @Prompt.
2) Turn the repeated list "Midas":"NoCache" into a one letter variable 'm'.
3) Inside the iterative loop, replace the repeated computed list "Body":("Paragraph "+@Text(p)); into variable 'bp'
4) Turn the repeated string "+HIDE_READ +HIDE_PREVIEW_Read" into a two letter variable 'hf' (for hide formula).
5) Turn the repeated @DocumentUniqueID into a single character variable 'u'.

c := "1) Those which do not start with D":"2) Those with images":"3) Those with the substring 'Raven' in them";
m := "Midas":"NoCache";
u := @DocumentUniqueID;
hf := "+HIDE_READ +HIDE_PREVIEW_Read";
choice := @Prompt([OkCancelList]; "Select criteria"; "Select which paragraphs to hide from read mode:"; c[1]; c);
p := 1;
t := @DbCommand(m; "GetCount"; u; "Body"; "Paragraph");
@For(p:=1; p <= t; p := p+1;
   bp := "Body":("Paragraph "+@Text(p));
   @If(@Begins(choice; "1");
              @If(!@Begins(@DbCommand(m; "Text"; u; bp); "D");
                      @DbCommand(m; "ParagraphStyle"; u; bp; hf); "");
          @Begins(choice; "2");
              @If(@DbCommand(m; "GetCount"; u; bp; "Graphic") > 0;
                      @DbCommand(m; "ParagraphStyle"; u; bp; hf); "");
          @Begins(choice; "3");
              @If(@Contains(@DbCommand(m; "UnformattedText"; u; bp); "Raven");
                      @DbCommand(m; "ParagraphStyle"; u; bp; hf); "");
""));
SELECT @All

Tip 2: If the same action happens as a result of separate tests, collapse nested ifs and save boolean

1) Since the @DbCommand(m; "ParagraphStyle"; ""; u; bp; hf); is repeated, separate it out and save condition in boolean variable 'do_it'

c := "1) Those which do not start with D":"2) Those with images":"3) Those with the substring 'Raven' in them";
m := "Midas":"NoCache";
hf := "+HIDE_READ +HIDE_PREVIEW_Read";
u := @DocumentUniqueID;
choice := @Prompt([OkCancelList]; "Select criteria"; "Select which paragraphs to hide from read mode:"; c[1]; c);
p := 1;
t := @DbCommand(m; "GetCount"; u; "Body"; "Paragraph");
@For(p:=1; p <= t; p := p+1;
   bp := "Body":("Paragraph "+@Text(p));
   do_it := @If(@Begins(choice; "1") & !@Begins(@DbCommand(m; "Text"; u; bp); "D");
                              @True;
                          @Begins(choice; "2") & @DbCommand(m; "GetCount"; u; bp; "Graphic") > 0;
                              @True;
                       @Begins(choice; "3") & @Contains(@DbCommand(m; "UnformattedText"; u; bp); "Raven");
                              @True;
                              @False);
   @If (do_it; @DbCommand(m; "ParagraphStyle"; u; bp; hf); "");
);
SELECT @All

Tip 3: Combine separate tests with ands and ors

This tip does not always make sense, since there are no short circuited expressions as there are in C/C++ and Java.  This means that all tests will be performed, even ones with side effects, so be careful.
1) Combine the separate choice tests with parantheses and 'or' vertical bars.

c := "1) Those which do not start with D":"2) Those with images":"3) Those with the substring 'Raven' in them";
m := "Midas":"NoCache";
hf := "+HIDE_READ +HIDE_PREVIEW_Read";
u := @DocumentUniqueID;
choice := @Prompt([OkCancelList]; "Select criteria"; "Select which paragraphs to hide from read mode:"; c[1]; c);
p := 1;
t := @DbCommand(m; "GetCount"; u; "Body"; "Paragraph");
@For(p:=1; p <= t; p := p+1;
   bp := "Body":("Paragraph "+@Text(p));
   @If((@Begins(choice; "1") & !@Begins(@DbCommand(m; "Text"; u; bp); "D")) |
           (@Begins(choice; "2") & @DbCommand(m; "GetCount"; u; bp; "Graphic") > 0) |
           (@Begins(choice; "3") & @Contains(@DbCommand(m; "UnformattedText"; u; bp); "Raven"));
                @DbCommand(m; "ParagraphStyle"; u; bp; hf);
                ""
          )
);
SELECT @All

Well, there you have it.  It still isn't pretty, but it is a whole lot cleaner than the original.  Is there more I could have done?  I'd be happy to hear any feedback.

Copyright 2004 Genii Software Ltd.

What has been said:

No documents found