Ben Langhinrichs

Photograph of Ben Langhinrichs

E-mail address - Ben Langhinrichs







Recent posts

Wed 18 Sep 2019

Perils of PDF 5: Data Confusion



Mon 16 Sep 2019

About that email in Notes



Mon 9 Sep 2019

Perils of PDF 4: Missing and obscured data


November, 2019
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

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