Hello Community,
I've run into a mystery with an arcade expression that I wonder if anyone here might be able to explain. I was able to make it work fine by switching the order of variable assignment, but I can't figure out why that worked and it's bothering me.
What happened: I set variables t, d, & s with values that I use to run a simple calculation at the end of the script. Variables t & d simply grab an integer out of two different feature fields, and s grabs a feature domain code and then uses that as a key to retrieve a value from a hard-coded dictionary. The assignment order shouldn't really matter so long as I have all three values that I need at the time of calculation, which I do. And yet, it does.
The offender is var s. When assigned before t & d, the script won't pass validation and throws a Type Error saying that it expects a string. So it thinks that $feature.GRADE is not a string when I feed it to my dictionary to retrieve the value. Unable to find a fix by doing null checks and explicit type casting, a coworker of mine jokingly told me to move var s underneath t & d. So std -> tds. For reasons, it made the error go away, the expression validated, and testing seems to indicate that it works fine.
Just wondering if anyone @ESRI might have some insight into what could be making this occur. Is this a bug?
Code snippet below.
Thanks in advance!
var pipeGradeDict = {
"A24 - 24000": 24000,
"A25 - 25000": 25000,
"A283 Gr B - 27000": 27000,
"A30 - 30000": 30000,
"B - 35000": 35000,
"HDPE": 0,
"HDPE - 3408": 0,
"HDPE - 3608": 0,
"HDPE - 4710": 0,
"PE 3408": 0,
"PE-C FIBERSPAR 1500": 0,
"PE-C FIBERSPAR 750": 0,
"PE-C FLEXPIPE 150": 0,
"PE-C FLEXPIPE 300 / 301": 0,
"PE-C FLEXPIPE 601": 0,
"RI": 0,
"UNK": 0,
"WPB - 35000": 35000,
"WPHY52 - 52000": 52000,
"WPHY60 - 60000": 60000,
"WPHY65 - 65000": 65000,
"WPHY70 - 70000": 70000,
"X24 - 24000": 24000,
"X25 - 25000": 25000,
"X30 - 30000": 30000,
"X35 - 35000": 35000,
"X40 - 40000": 40000,
"X42 - 42000": 42000,
"X42/X52 - 52000": 52000,
"X42V - 42000": 42000,
"X45 - 45000": 45000,
"X46 - 46000": 46000,
"X50 - 50000": 50000,
"X52 - 52000": 52000,
"X52/X60 - 60000": 60000,
"X52M - 52000": 52000,
"X52V - 52000": 52000,
"X56 - 56000": 56000,
"X60 - 60000": 60000,
"X60C - 60000": 60000,
"X60K - 60000": 60000,
"X60M - 60000 THERMAL MECHANICAL ROLLED": 60000,
"X60V - 60000": 60000,
"X65 - 65000": 65000,
"X65M - 65000 THERMAL MECHANICAL ROLLED": 65000,
"X70 - 70000": 70000,
"X70M - 70000 THERMAL MECHANICAL ROLLED": 70000,
"XH60 - 60000": 60000,
"XK60 - 60000": 60000,
"XV65 - 65000": 65000,
"Y35 - 35000": 35000,
"Y42 - 42000": 42000,
"Y46 - 46000": 46000,
"Y52 - 52000": 52000,
"Y60 - 60000": 60000,
"Y65 - 65000": 65000,
"Y70 - 70000": 70000
};
//Put formula in variable for use in SMYS field
//Specified minimum yield strength (SMYS) is related to the pressure inside a pipe by Barlow's formula:
//P = 2St/D, where t is the pipe thickness in inches, and D is the outside diameter, also in inches.
//Error handling: if s & t values empty, set to 0. if d value empty, set to 1023 (0/1023 = 0)
var t = IIF(IsEmpty($feature.WALL_THICKNESS), 0, $feature.WALL_THICKNESS) //1022 = RI, 1023 = UNK
var d = IIF(IsEmpty($feature.OUTSIDE_DIAMETER), 1023, $feature.OUTSIDE_DIAMETER) //1022 = RI, 1023 = UNK
var s = IIF(IsEmpty($feature.GRADE), 0, pipeGradeDict[$feature.GRADE]) //arcade errors if this is above vars t & d??
var smysCalc = Floor(2*s*t/d, 0)
Thanks Gregory for sharing this, anytime you find something doesn't make sense please do let us know.
There is sure a bug here, if this is the code you are using. I expect the order matter when you have an early exist (like a check with a return) where the rest of the code won't be checked even if it has a bug. But that doesn't seem to be the case for your code
Can you share what Pro were you using? what database platform is it on (enterprise ( if yes is it oracle/sqlserver etc.. ) or filegdb/mobile etc) and maybe the schema of your class? an XML export with no data is sufficient.
that will help us narrow down the cause.
one more thing , make sure to use haskey to check the dictionary pipeGradeDict otherwise you will get a field not found error when the value isn't part of the dictionary.
Keep in mind the arcade validation uses the first row in the table as a candidate for validation, if table is empty, we create a dummy row with default values initialized for validation.
the string type expected error can only happen if you are passing a number as the key where a string is expected.
p.s. I couldn't reproduce with 3.1 , 3.0 or 2.9.10 when I move the line up t & d validation just works, yet again I created my own table with your fields there might be more to your specific Pro/dbms schema and data.
Thanks for the reply, and apologies for the delayed response!
I'm currently using ArcGIS Pro 2.9.9. The data is currently sitting in a local file gdb, which is a replica of our oracle sde.
I would love to share the xml; however, even the schema alone (which is massive) does contain potentially sensitive information about my company's assets/operations, and I like being employed 😁...
I realize that isn't much to go on, but please let me know if I can answer any other questions, or if you do end up finding something related to this issue.
Appreciate the support!
A workaround might be to create the dictionary as a feature table in your database and filter it?
var dict = FeatureSetByName($datastore, "Dictionary")
var grade = $feature.GRADE
var filtvalue = first(filter(dict,"Code = @grade"))['Value']
Thanks for the idea!