Hi folks,
Here is a method I find incredibly useful. It's another one of those things
I suspect a lot of you have already written but I haven't seen anyone
talking about it so I will.
This method allows you to write a formula as a text string referring to
object keys then pass the formula and cobj to the method. The key values
are inserted into the formula and the result is returned. Optionally you
can specify a result key and the result will be written to the object as
well.
The method assumes you're using Canon's OBJ component. If not just
substitute whatever you use for getting/setting object values. This is v15
compatible. It could easily be modified to use the new dotnotation in v16.
Note that you must wrap key names in the backtic (`). I needed something to
identify a key from anything else and there are not a lot of unique options
on the keyboard anymore.
The actual calculation uses #4DEVAL so your formula can include:
key names
4D methods
project methods
process and IP variables
constants
A formula might look like this: " ((`y` * 23) + `abs.frt`)^ `123.frt`"
The extra spaces are just for readability  they are ignored in execution.
All keys are read as REAL. Text keys are converted to real as are long and
boolean keys. Missing keys are zero.
If I want to assign the result of the formula to a key in the object:
" `x`= ((`y` * 23)+`abs.frt`)^ `123.frt`"
If x doesn't exist it's created. If it does it's updated.
Finally the 3rd para allows you to specify writing the result as text in
the object. Why you do that? There are good reasons for managing all values
in a cobj as text (it's easier). But this also allows you to do things
like date operations and save the result as a date string, for example.
Here are few uses:
$formula:="`x` = Cos(`y`) "
$formula:="`x`=((`y`*23) + `abs.frt`) ^ `123.frt`"
$formula:="`x` = (<>IPconstant * processConstant)" // referring to keys is
optional
$formula:="`newDate`=String(Add to date(Current
date;`year`;`month`;`day`);Internal date long)"
This last one is particularly cool. It works because #4DEVAL simply
evaluates the string passed to it.
$formula:="<!#4DEVAL "+$formula+">" //calculation
PROCESS 4D TAGS($formula;$result)
The result is text even though the calculation may return a real (or any
other) value. Here's where the 3rd parameter comes in because it allows me
to write this text result to the object.
Consider an object:
{
"year": 0,
"month": 1,
"day": 23,
}
I pass the formula above:
$x:=OB_calculate ($obj;$formula;True)
The object is updated to:
{
"year": 0,
"month": 1,
"day": 23,
"newDate": "March 16, 2018"
}
and $x is 162018 which is simply the numbers of the date string and
meaningless.
I developed this method to manage listboxes where the data for the listbox
is in a hidden object array. This is a handy interface approach. It makes
it possible to display a listbox where the calculations involve a large
number of other values. Using arrays for the listbox data would typically
involve a lot of hidden arrays. Using an object array involves only the
columns of interest with the other data in the object.
With this method I can update the object array as required. And since the
formulas are all text based I don't even have to hard code the business
logic of the formulas. I could allow end users to define their own business
logic for their data, for instance. Or tailor how an interface works for
particular instances. You can do that now too, of course, but this is
probably a little easier.
Note on string objects. In v15 using
$real:=OB get($obj;"key";Is real)
doesn't correctly convert a text value if it contains commas. Using the Num
function accounts for this and also allows you to control the separator so
I suggest using:
$real:=Num(OB get($obj;"key";Is text))
If the key is already a real this won't matter and if it's text it will be
handled correctly including currency symbols.
Final note on key names  $pattern doesn't check for spaces in key names.
This is technically allowed but usually discouraged. If you need to
recognize key names with spaces tweak $pattern to suit. It does find
hyphenated keys, eg. "padright".
Be sure to add your preferred error checking code!
=================================================
// OB_calculate
// Written by: Kirk as Designer, Created: 01/21/18, 11:17:23
// 
// Method: OB_calculate (cobj; text{;bool}) > real
// $1 is a cobj
// $2 is a formula
// ex: ((`y`*23)+`abs.frt`)^`123.frt`
// or: `x`= ((`y`*23)+`abs.frt`)^`123.frt // write result to x
// $3 is TRUE to write result to object as text  default is false
// ignored if result isn't written to object
// $0 is result
// Purpose: The formula will be populated with key values and calculated
// All keys are treated as REAL but the keys may be text, real, long,
bool or date
// Missing keys = 0
// Key names must be wrapped in backtic: `thisKey`
and not contain spaces
// any formatting in the key values will be ignored
// This can also be used to simply write a value to an object.
// The result key, if specified, will be added if it's not there
// negative numbers in the object must be specified as 1234
// can not user parens to indicate negatives
// Formula may contain 4D expressions and process or IP vars
C_OBJECT($obj;$1)
C_TEXT($2;$formula)
C_BOOLEAN($3;$isText)
C_TEXT($resultKey)
C_REAL($0;$value)
C_LONGINT($i;$n)
C_TEXT($result;$pattern;$key;$str)
$obj:=OB_New
$obj:=$1
$formula:=$2
If (Count parameters>2)
$isText:=$3
End if
If (Position("=";$formula)>0)
$resultKey:=Substring($formula;1;Position("=";$formula)1)
$resultKey:=Replace string($resultKey;"`";"")
$formula:=Substring($formula;Position("=";$formula)+1)
End if
// 
$pattern:="`([\\w\\d\\.

]+)`" // for finding keys
ARRAY LONGINT($aLen;0)
ARRAY LONGINT($aPos;0)
While (Match regex($pattern;$formula;1;$aPos;$aLen))
$key:=Substring($formula;$aPos{1};$aLen{1})
$value:=OBJ_Get_Real ($obj;$key)
$str:=Substring($formula;$aPos{0};$aLen{0}) // the entire match string
$formula:=Replace string($formula;$str;String($value))
End while
// 
$formula:="<!#4DEVAL "+$formula+">" //calculation
PROCESS 4D TAGS($formula;$result)
// 
$0:=Num($result)
Case of
: ($resultKey="")
: ($isText)
OBJ_Set_Text ($obj;$resultKey;$result)
Else
OBJ_Set_Real ($obj;$resultKey;Num($result))
End case

Kirk Brooks
San Francisco, CA
=======================
*We go vote  they go home*
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:
http://lists.4d.com/faqnug.htmlArchive:
http://lists.4d.com/archives.htmlOptions:
http://lists.4d.com/mailman/options/4d_techUnsub: mailto:
[hidden email]
**********************************************************************