Difference between "Normal Mode" and "Legacy Mode" in ReportMagic macros

As one of the ReportMagic developers, recently I received a Jira ticket asking to add a help example to the [ServiceNow.List:] macro (this macro retrieves a list of objects from a ServiceNow system), and the customer who provided the initial feedback was confused about “Normal Mode” and “Legacy Mode” when using macros in report templates.

So this post is a brief explanation about the differences between the two modes, a little bit of history and some examples and explanations.

A Brief History (of time)

More than 10 years ago when I started working as a developer on ReportMagic, there were something like a few dozen macros with which to manipulate data and create the output needed for reports (today, there’s close to 600 macros!), and everything was essentially manipulated as strings (text). This was all well and good in the beginning, because most things (even numbers) could be treated as strings and manipulated fairly simply internally in the code.

However, when we started dealing with much more complex input data, such as JSON (JavaScript Object Notation), and data queried dynamically from remote systems (where the data might not be well-formed), it became much more challenging just to treat everything as text for various reasons.

For example, one issue with calculations based on text is having to convert to a numerical format in order to perform addition, subtraction and so on. In other words, “1” + “2” (quotes indicate text strings) should generate “3”, but in computer code adding two strings is usually a concatenation i.e. “12” - not the desired answer in this case.

Dates and times (coders use the nomenclature ‘DateTimes’) when represented as text invariably necessitate some parsing, which leaves to potential ambiguity due to different date formats used around the world. For example, without specifying a particular date format, “05/06/2025” could mean 5th of June 2025 in the UK, or May 6th 2025 in the US date format. You might use something completely different such as “25/06/05” or “2025-06-05”. There are literally dozens of combinations. Dates and times, when represented as text, is very very bad!

JSON can represent pretty much any data (objects), but it can also contain special characters (single quotes, backticks, double quotes, commas, and on) which made it very challenging to integrate into the macro ‘language’ - as this itself may use quotes, commas and other characters to delineate where the macro definition, and the data.

We felt that macro-generated data should be manipulated (and stored as variables) as strongly-types objects. For example, a number could be stored as an integer (whole number) or a float / double (with decimal places), and a Date Time would be stored as a DateTime object. We also store JArrays and JObjects, which are simply the machine code equivalent of JSON data structures.

To maintain backwards compatibility, we kept the ‘old’ behaviour and called it “Legacy Mode” - this basically regards everything as a string (yes, even numbers). We also introduced “Normal Mode” where the data is stored as a more representative data type.

Normal Mode is now the default in Report Studio (though you can switch to Legacy Mode in the UI), unless you override it with “mode=legacy” in the macro definition.

Using Legacy and Normal Modes

In Report Studio, the default is Normal Mode (as shown below) but you can switch to Legacy Mode by if you wish. To override the selected mode, simply add one of the following to each macro:

  • mode=Normal
  • mode=Legacy

This is not case-sensitive, i.e. you can use mode=normal and other variants.

Here’s the button in all its glory:

Some people still use Legacy Mode today (yes, it can be a learning curve to convert existing reports to Normal Mode). Here follow a few examples and description of the possible issues.

Consider this macro:

[CronRunDate: value="0 0 12 ? 1/2 THU#3 *", cronScheduleType=Next, storeAs=NextRunDate, mode=legacy]

The output is stored as a string as shown below in a progress page screenshot. You can hover over the “T” icon for a tooltip which shows “String”.

image

As you can see, the “T” next to the value means it’s a text variable.

But if you run it in Normal Mode:

[CronRunDate: value="0 0 12 ? 1/2 THU#3 *", cronScheduleType=Next, storeAs=NextRunDate, mode=normal]

you’ll see it’s stored as an actual DateTime as indicated by the small calendar icon in the progress page!

image

Perhaps a better example of the challenges of Legacy Mode would be some list-based macro examples. These are particularly challenging when using Legacy Mode because the generated list if typically stored and manipulated as a string of items delimited by a special character (such as a semi-colon).

In Legacy Mode, say we want to add four numbers to a list, we could do it like this:

[List.Add: value=a, mode=Legacy, storeAsHidden=MyList]
[List.Add: value=b, mode=Legacy, storeAsHidden=MyList]
[List.Add: value=c, mode=Legacy, storeAsHidden=MyList]
[List.Add: value=d, mode=Legacy, storeAsHidden=MyList]

which then produces a text variable “MyList” represented as:

a;b;c;d

image

Note that the “delimiter character” (semi-colon) can be changed in the macro to any character you like.

Typically this variable we just generated would then be used as the input to another macro (such as a ForEach macro to iterate them in a loop), or used as the input to various string macros to split the data into each item.

The big problem with all this Legacy Mode stuff is that in real-world scenarios customers, and our own report authors, would have to construct rather large and unwieldy macros to parse huge text strings in variables, split them, find indexes, try to ignore weird characters, search and replace anything known to cause breakages, and generally suffer immensely trying to process everything as text. Things had to change!!

The Solution

The answer, in most cases, is to use Normal Mode in your macros.

If we ran one of the previous List macro in Normal Mode e.g.

[List.Add: value=a, mode=Normal, storeAsHidden=MyList]
[List.Add: value=b, mode=Normal, storeAsHidden=MyList]
[List.Add: value=c, mode=Normal, storeAsHidden=MyList]
[List.Add: value=d, mode=Normal, storeAsHidden=MyList]

we end up with the MyList variable containing a magical data structure known as a JArray. As you can see below there is one JArray (denoted by the enclosing ‘[’ and ‘]’ characters) that contains 4 items.

image

Hover your mouse over the “JS” icon and it shows “JArray - 4 items”.

The real versatility of Normal Mode can be demonstrated with an example such as the following:

[Object: value=<json>{ "a" : "X", "b" : 2 }</json>, =>TheObject]
[.:TheObject.b, storeAs=B]

The first [Object:] macro creates an object (coined a JObject) from some JSON - I used a text representation of the JSON here, but in most scenarios this would have been retrieved from some external system - such as a web query or database perhaps - and stored in a variable.
e.g

[Object: value={SomeVariable} =>TheObject]

The second macro is actually a special “shorthand” for the [Calculate:] macro, which uses the the notation:

[.:]

followed by the name of the variable and a property, in this case the variable is called TheObject, and we want to obtain the value of the property “b” (which is 2).

Here, you can see that we store the result in a variable called B, and the tally icon demonstrates that it’s stored as an Int64 (a 64-bit integer) - basically, a whole number.

image

Now just imagine trying to use Legacy Mode to process the “TheObject” variable treating it as text - it can be quite challenging to parse that for the data you want and use that elsewhere in ReportMagic!

Help Examples

Most of the ReportMagic macro help examples indicate whehter they are intended to run in Normal Mode only or Legacy Mode only. Some examples can still be used in either mode.

Here’s what the help typically looks like:

Note that you can find more information about the various List macros (and so much more) in the ReportMagic help or in the Docs App, e.g. here.

The Future

We strongly recommend getting to grips with Normal Mode when using macros - as it’s so much more powerful and (once you have gotten the hang of it) can actually result in fewer (and more elegant) macros required to process data in order to produce your reports.

Most of the macros now properly support Normal Mode input and output, but there are still a few stragglers out there that haven’t yet been fully converted, or perhaps may not behave exactly how you want - but we are working towards 100% full support of Normal Mode in the near future.

Final Thoughts

Don’t be afraid of using Normal Mode - it’s quite intuitive and very powerful once you take the plunge! And let us know if you have any particularly challening issues or need help with it.

4 Likes