Modscript: Variant() and GetFieldValue Guide

1
The last two days, I tried to learn more on Modscript. Especially I did focus on GetFieldValue
and the newly introduced Variant() data type.

This report is divided into the following sections:
Background
Assignments to variables of type Variant?
What is the output of Shell.Item().GetFieldValue()?
A Variant() of subtype String is not a chaiscript string
Date calculation
Conclusion


Let's start...

Background

For this analysis I was in need for more details on the variable types. There are
three important functions available (but not documented in the Modscript guide):

type_name(variable)
A chaiscript function which returns the name of the type of the variable

TypeName(variable)
A SBM extension which returns the name of the type of the variable for
native variables, but returns the internal type for variables of type Variant().

VarType(variable)
Same as TypeName() but returns a number instead of a string.
Numbers are taken from VBS. Here are some examples for values returned by VarType().

0 = vbEmpty - Indicates Empty (uninitialized)
3 = vbLong - Indicates a long integer
7 = vbDate - Indicates a date
8 = vbString - Indicates a string
11 = vbBoolean - Indicates a boolean


type_name() and TypeName() are almost the same, but they differ for Variant() data types:
var v = Variant();
v = "abc";
TypeName(v); // this returns "String"
type_name(v); // this returns "Variant"
VarType(v); // this returns the integer number 8 (vbString)


Assignments to variables of type Variant?

Assume the following code:
global v = Variant();

If we want to know whether something useful has been asigned to "v", then just check for "VarType(v) == 0".

Now I had the required tools to analyse the output of GetFieldValue()...

What is the output of Shell.Item().GetFieldValue()?

Assume the following code:
global v = Variant();
Shell.Item().GetFieldValue(SBMFieldName, v);


I tested the output values with several field types
Field			    VarType(v)	    v.to_string()
Illegal field name not modified not modified
Date/Time 8 2018-03-02T10:00:00+00:00
Multi-Relational 8 ,1842,2058,
Single-Relational 8 1842
Numeric 8 1234
Single Selection 8 11696
Checkbox 8 1
User 8 0
Multi-User 8 ,

Outcome:

  • GetFieldValue will always output a Variant() of subtype String
  • Except for Date/Time fields, there is no difference to Appscript
  • Date/Time fields now return an ISO 8601 time string


Note:
These results are different for any script converted automatically from Appscript.
In this case the initial call to ConvertedFromAppScript() will modify the behavior
of GetFieldValue().


A Variant() of subtype String is not a chaiscript string

GetFieldValue() output Variant() of subtype String only. Unfortunately it is not possible to apply
chaiscript string functions (like size or substr) directly to a Variant() of subtype String.
Always convert to string first (to_string() function).

The old VBS funktions are still supported, so we can use Len(), Mid() and others. These
VBS functions seem to work nicely with both Variant() of subtype String and chaiscript strings:
var v = Variant();
v = "abcd";
var s = "xyz";

size(v); // error, does not work
size(v.to_string()); // ok, returns 4
size(s); // ok, returns 3
Len(v); // ok, returns 4
Len(s); // ok, returns 3
substr(v, 1, 2); // error, does not work
substr(v.to_string(), 1, 2); // ok, returns "bc"
substr(s, 1, 2); // ok, returns "yz"
Mid(v, 1, 2); // ok, returns "ab"
Mid(s, 1, 2); // ok, returns "xy"


Notes:

  • The start position in the substr() command starts with 0, the start position argument
  • for Mid() starts with 1.
  • The VBS compatible string functions return a Variant() of subtype String
  • The native Chaiscript functions (size, substr) return a native Chaiscript string.


The use of Len, Mid and friends seem to be a good solution, however they are not
documented in the Modscript guide. The question will be, can we (as a SBM user) rely on
a long term presence of these VBS functions in Modscript. If so, they should be documented.

I see a problem for new Modscript users here: The native Chaiscript string functions
will not work that well together with the GetFieldValue() output and the existence
of the VBS compatible functions is not mentioned.

Date calculation

Assume the calculation of a target date, based on the submit date with Appscript:
Dim v
Call Shell.Item.GetFieldValue("SUBMITDATE", v)
v = v + 24*60*60 * 7 ' one week later
Call Shell.Item.SetFieldValue("TARGETDATE", v)


This code pattern was possible, because v was returned as seconds after 1st Jan 1970.
Now a ISO 8601 string is returned, which requires a different approach:
global v = Variant();
Shell.Item().GetFieldValue("SUBMITDATE", v); // v is Variant of subtype String
v = Ext.DateToDbLong(v); // v is Variant of subtype Long
v = v + 24*60*60 * 7; // one week later
v = Ext.DbLongToDate(v); // v is Variant of subtype Date
Shell.Item().SetFieldValue("TARGETDATE", v); // v is accepted although it is not a ISO 8601 string


Notes:

  • Usually Chaiscript does not allow reusage of variables with different types. This
  • possible only, because v is of type Variant();
  • For date/time fields, SetFieldValue() accepts either strings (ISO 8601 format) or
  • Variant() objects of subtype Date.



Conclusion


  • Mixing Chaiscript functions with variables of type Variant() needs extra care (e.g. to_string()).
  • The Modscript type "Variant()" allows reuse of variables also in cases where the type changes.
  • Code pattern for date/time calculation is different compared to Appscript.
  • The VBS string functions seem to be available in Modscript, but these functions are not documented in the Modscript guide.


I hope this small guide clarifies some topics and will help others to get the best
out of Modscript.

Have fun...
Like
Responses (6)
  • Accepted Answer

    Friday, March 02 2018, 12:35 PM - #Permalink
    0
    Awesome bit of work Oliver! Thank you!
    The reply is currently minimized Show
  • Accepted Answer

    Tuesday, March 20 2018, 06:16 PM - #Permalink
    0
    Thanks for your continued research into ModScript. In order to create a new script environment that can support converted AppScripts with a potential one to one behavior, we needed to introduce many things into ModScript that are mainly there for the purpose of converted AppScripts. In general, Variant is one of those things (however, Variant is also used to simplify many ModScript functions, allowing them to take int, string, double, etc, and "doing the right thing").


    To explain the different behavior for Variant-date, AppScript had an internal compatibility version that was changed when we needed to fix defects but didn't want to affect old scripts that depended on the current behavior. One could call SetCompatibilityVersion to get the new behavior, but the old, buggy behavior was kept as default. In reality, the only place this affected was how date/time fields worked. For ModScript, we decided that the newest version of the behavior is the best practice for usage, so ModScript sets the newest possible compatibility version for code it shares with AppScript. However, when converting scripts, we need to reverse this assumption, and actually start with the original behavior, only switching to the newer behavior if the script invokes SetCompatibilityVersion. To do this, we introduce the call ConvertedFromAppScript to scripts that are converted, which sets the compatibility version back to 0. We then honor calls to SetCompatibilityVersion inside the script.


    To answer the question about the longevity of AppScript artifacts in ModScript, they are here to stay. They were introduced so that scripts could be converted, and they will remain so that converted scripts can keep running. We have documented these functions in 11.4, and I apologize for not documenting them earlier.


    Yes, many functions in ModScript require usage of Variant, which was not our intent. In 11.4, we have introduced functions like Field.GetValueString(), Field.GetValueInt(), and Field.GetValueTimeT() which will return the value as the requested ChaiScript data type. We have made TimeT much more usable, and you can now get and set fields using TimeT. This should make working with dates much more precise. TimeT has timezone guarantees as well as Time Zone conversion tools. Yes, you can still use Variant, but our goal is to minimize the ModScript coder's need to depend on the AppScript carry-over artifacts.
    Like
    • Oliver Kraus
      more than a month ago
      Thanks a lot for your feedback. Great that we can expect the VBS functions to be there.
    • Diana
      more than a month ago
      Hi Don,

      I am trying to set the Change Request ID to a single relational field in an aux table but I get the error message "Change Request' has an invalid selection. Please select a valid value to complete this transition."

      Below is my code to give you a better understanding of what i mean.

      Thanks!

      var newAuxRecord = Ext.CreateVarRecord(Ext.TableId("TSM_SAST_COMPLIANCE"));


      newAuxRecord.SetFieldValue("CHANGE_REQUEST", Shell.Item().GetId());
      newAuxRecord.SetFieldValue("CONFIGURATION_ITEM", Shell.Item().GetFieldValueInt("AFFECTED_CI"));
      newAuxRecord.SetFieldValue("TITLE", Shell.Item().GetFieldValueString("TEMP_SAST_REFERENCE"));
      newAuxRecord.SetFieldValue("EXEMPTION_SR_REF", Shell.Item().GetFieldValueString("TEMP_EXEMPTION_SR_REF"));


      var result = newAuxRecord.QuickSubmitToAux();
    • Don Inghram
      more than a month ago
      Hi, Diana. Is it possible that you are running this ModScript in the submit transition of an item? If so, it is likely that the validation steps for the new aux item are trying to verify that the item exists, but the item does not yet exist as it is still being submitted. If this is the case, you may wish to change the submit into a 2 step process, where the submit transition goes into a Decision state with only a single exit transition. Make the exit transition a quick transition, and make the ModScript run in that transition. Then, the Submit transition will have completed by the time you are trying to use the item in a relational field in a different table.

      If this is not the case or does not help, please contact Tech Support, and we can work together to resolve the issue.
    The reply is currently minimized Show
  • Accepted Answer

    Diana
    Diana
    Offline
    Thursday, December 27 2018, 07:14 AM - #Permalink
    0
    Hi Don. Yes, my script was on a submit transition. I did try putting the script on a transition after the decision but it also didn't work. I ended up adding a transition to the state and triggering it by the submit transition. Thanks for your help!
    • Don Inghram
      more than a month ago
      Diana, good thinking, I'll remember that. I'm glad you resolved the problem.
    The reply is currently minimized Show
  • Accepted Answer

    Thursday, December 27 2018, 11:05 PM - #Permalink
    0
    Is this a case of mixing chaiscript type variables and VBScript types? For example, would this work? The following adds "CInt" and "CStr" calls to convert the 2nd param to a VBScript type.


    newAuxRecord.SetFieldValue("CHANGE_REQUEST", CInt(Shell.Item().GetId()));
    newAuxRecord.SetFieldValue("CONFIGURATION_ITEM", CInt(Shell.Item().GetFieldValueInt("AFFECTED_CI")));
    newAuxRecord.SetFieldValue("TITLE", CStr(Shell.Item().GetFieldValueString("TEMP_SAST_REFERENCE")));
    newAuxRecord.SetFieldValue("EXEMPTION_SR_REF", CStr(Shell.Item().GetFieldValueString("TEMP_EXEMPTION_SR_REF")));
    • Don Inghram
      more than a month ago
      Paul, Variant can be constructed directly from a ChaiScript int, string, or double, so that is not necessary. CInt and CStr are sort of weird, what they do is take a Variant input and return a Variant with the same content, but internally represented as an int or string. They are not really intended for ModScript, but are supported for backward compatibility with AppScript. ModScript is intended to be strictly typed, but as we introduced Variant for backward compatibility, it muddies the waters a bit. As ModScript has matured, it does not force you to use Variants in your scripts the way it did originally. However, some of the ModScript API still accepts Variant as an expedient way to accept any input (int, string, double) and do the expected thing. The documentation has also been greatly improved to help the script author understand the inputs and outputs of any given function.
    The reply is currently minimized Show
  • Accepted Answer

    Thursday, February 21 2019, 05:23 PM - #Permalink
    0
    Just adding a link to a comment I made in part 14 of Don Ingram's excellent ModScript series.

    My comment has some ModScript for a "VarInfo" function that returns a string with every bit of information I can find about the type of it's param. I've been using that function a lot as I go through the ModScript learning process. I'm discovering what ModScript doesn't do (postfix operators like "++") along with what it does do (transitions! yea!).
    The reply is currently minimized Show
  • Accepted Answer

    Wednesday, February 27 2019, 02:16 PM - #Permalink
    0
    so if I'm reading this correctly instantiating a variant like so:

     
    global strSubtaskIds = Variant();


    would in fact be instantiating it as a modscript variant and not a chaiscript variant?
    The reply is currently minimized Show
Your Reply