“If” Script Step

The file I inherited includes several scripts that feature a single “if” script step:

If get script parameter = “x”
Do stuff
Do stuff
Do stuff
End if
Exit

For long scrips, this needlessly indents the script by one level. My thought process is:

If get script parameter = “x”
#Continue
Else
Exit script
End if

Do stuff
Do stuff
Do stuff

Exit script

Clearly, this is a matter of personal taste in coding, but I wonder if there’s a generally accepted “best practice.”

1 Like

This is called the Early return pattern.

In your example, I would use not equals (either <> or ) instead of equals ( = ) and avoid the

Else If

statement to make it even cleaner:

If Get(ScriptParameter) ≠ "x"
  Exit Script
End If

# if we get here, everything is OK
Do Stuff
Do Stuff
...

See also the Pyramid of Doom

5 Likes

Thank you, @xochi I appreciate your info and links. The Medium article was very helpful.

2 Likes

I wanna add to @xochi 's excellent answer. One common pattern in FM scripts that I see frequently, and use personally is a "single-pass loop" for early exits and error trapping. This pattern allows you to add multiple guard clauses or exit conditions, but still centralize the actual Exit Script step at the end so that you can do some boilerplate logging and script result formatting. This can make script flow easier to reason about.

Example

Loop
	# Single-pass loop

	# Put your main logic in here.

	Exit Loop If [ If ( WrongContext() ; Let ( $error = "Wrong context!" ; True ) )]
	Exit Loop If [ If ( not IsBrowseMode() ; Let ( $error = "Must be in browse mode" ; True ) )]
	
	# If no records, exit *without* error (don't set $error)
	Exit Loop If [ Get(FoundCount) = 0 ]

	New Record
	Exit Loop If [ If ( Get(LastError) ; Let ( $error = "New Record: " & Get(LastError) ; True ) )]
	Set Field [ "Field1" ; "123" ]
	Exit Loop If [ If ( Get(LastError) ; Let ( $error = "Set Field1: " & Get(LastError) ; True ) )]
	Set Field [ "Field2" ; "987" ]
	Exit Loop If [ If ( Get(LastError) ; Let ( $error = "Set Field2: " & Get(LastError) ; True ) )]

	Commit Record
	Exit Loop If [ If ( Get(LastError) ; Let ( $error = "Commit: " & Get(LastError) ; True ) )]


	# End Single-pass loop
    Exit Loop If [ True ]
End Loop

# Centralized error handling
If [ $error ]
	Revert Record
	Perform Script [ "Log" ; "Uh oh, an error occurred: " & $error ]
	Show Custom Dialog [ "Error!" ; $error ]
End If

# Centralized Exit Script
Exit Script [ JSONSetElement ( "{}" ; [ "error" ; $error ; JSONString ] ) ]

NOTE: this is a purposely rudimentary example of error formatting, and a more sophisticated error trapping solution would use an error json object that always has the same properties (and a succinct custom function to create it). I just used strings for simplicity.

If you're interested in error trapping/handling and this pattern, check out @Bobino 's example files on the subject: Downloads – Accolade Plus Accolade

7 Likes

Thanks @jwilling for the shoutout. For anyone interested, the same demo file was used as the core material for a presentation I mentioned in this other thread: Error trapping advice - #7 by Bobino

1 Like