Use multiple operands simultaneoulsy with COMPUTE #89

Closed
opened 2026-02-20 10:14:04 -05:00 by deekerman · 12 comments
Owner

Originally created by @Ingegneus on GitHub (Jan 27, 2021).

I'm working with strings rn and it would be very nice if for example I was able to concat many operands (3 or more) together in one operation. It would be very convenient for other computations as well,

Originally created by @Ingegneus on GitHub (Jan 27, 2021). I'm working with strings rn and it would be very nice if for example I was able to concat many operands (3 or more) together in one operation. It would be very convenient for other computations as well,
deekerman 2026-02-20 10:14:04 -05:00
Author
Owner

@larkob commented on GitHub (Jan 27, 2021):

I had similar ideas and was thinking about adding a "template literal" functionality with "expression interpolation", so basically a way to do this: let var = `Some ${variable1} and some other ${variable2}` which would not only help to concatenate strings but also allow use of variables, mathematical expressions and if/else conditions.

Example showing who's turn it is:
Player ${playerName[current_player_number]}'s turn

Another example showing print "1 Card left" or "n Cards left":
${max - current} Card${max - current == 1 ? '' : 's'} left

Sounds a bit complex, but this functionality is already available in modern JavaScript, so it'd be quite easy to implement.

I could actually go ahead and do it, but it's probably worth posting it here before, so we can have some further discussion. One thing I'm still not sure about is whether to implement it as a COMPUTE operation or as something entirely new. With COMPUTE it would look something like this:

{
"func": "COUNT",
"collection": "myCollection"
},
{
"func": "COMPUTE",
"operation": "literal",
"operand1": "Amount: ${COUNT}",
"variable": "result"
}
@larkob commented on GitHub (Jan 27, 2021): I had similar ideas and was thinking about adding a "template literal" functionality with "expression interpolation", so basically a way to do this: ``` let var = `Some ${variable1} and some other ${variable2}` ``` which would not only help to concatenate strings but also allow use of variables, mathematical expressions and if/else conditions. Example showing who's turn it is: ```Player ${playerName[current_player_number]}'s turn``` Another example showing print "1 Card left" or "_n_ Cards left": ```${max - current} Card${max - current == 1 ? '' : 's'} left``` Sounds a bit complex, but this functionality is already available in modern JavaScript, so it'd be quite easy to implement. I could actually go ahead and do it, but it's probably worth posting it here before, so we can have some further discussion. One thing I'm still not sure about is whether to implement it as a COMPUTE operation or as something entirely new. With COMPUTE it would look something like this: ``` { "func": "COUNT", "collection": "myCollection" }, { "func": "COMPUTE", "operation": "literal", "operand1": "Amount: ${COUNT}", "variable": "result" } ```
Author
Owner

@larkob commented on GitHub (Jan 27, 2021):

However, the most intriguing way to implement this would be via the applyVariables function, because that would work for any operation without the need for a COMPUTE:

{
"func": "LABEL",
"label": "<labelId>",
"applyVariables:" [{
  "variable": "Amount: ${COUNT}",
  "parameter": "text"
}]
}
@larkob commented on GitHub (Jan 27, 2021): However, the most intriguing way to implement this would be via the applyVariables function, because that would work for any operation without the need for a COMPUTE: ``` { "func": "LABEL", "label": "<labelId>", "applyVariables:" [{ "variable": "Amount: ${COUNT}", "parameter": "text" }] } ```
Author
Owner

@larkob commented on GitHub (Jan 27, 2021):

I have the feeling we shouldn't mix regular variables with literals, though, so perhaps this is better:

{
"func": "LABEL",
"label": "<labelId>",
"applyVariables:" [{
  "literal": "Amount: ${COUNT}",
  "parameter": "text"
}]
}

Or:

{
"func": "LABEL",
"label": "<labelId>",
"applyLiterals:" [{
  "literal": "Amount: ${COUNT}",
  "parameter": "text"
}]
}
@larkob commented on GitHub (Jan 27, 2021): I have the feeling we shouldn't mix regular variables with literals, though, so perhaps this is better: ``` { "func": "LABEL", "label": "<labelId>", "applyVariables:" [{ "literal": "Amount: ${COUNT}", "parameter": "text" }] } ``` Or: ``` { "func": "LABEL", "label": "<labelId>", "applyLiterals:" [{ "literal": "Amount: ${COUNT}", "parameter": "text" }] } ```
Author
Owner

@ArnoldSmith86 commented on GitHub (Jan 27, 2021):

Sounds a bit complex, but this functionality is already available in modern JavaScript, so it'd be quite easy to implement.

I don't see how this is easy to implement unless you use eval. At least for your given examples.

I did actually think about something similar though. I pretty much decided not to add it but my idea was to add some very basic features in an expression that could even live one level higher:

{
  "clickRoutine": [
    {
      "func": "COUNT"
    },
    "w.widgetID1.height = w.widgetID2.height + v.var1 + v.var2",
    {
      "func": "COUNT"
    }
  ]
}

That would set property height of the widget with "id": "widgetID1" to property height of the widget with "id": "widgetID2" plus variables var1 and var2.

I would make this really restrictive though to avoid complexity and eval. Left hand only v.* or w.* and right hand the same plus basic math operations (+-*/ and boolean logic pretty much).

Numeric literals would also be fine. Maybe even strings.

And probably w[v.var1].height so you could use variables as widget IDs.

@ArnoldSmith86 commented on GitHub (Jan 27, 2021): > Sounds a bit complex, but this functionality is already available in modern JavaScript, so it'd be quite easy to implement. I don't see how this is easy to implement unless you use `eval`. At least for your given examples. I did actually think about something similar though. I pretty much decided not to add it but my idea was to add some *very basic* features in an expression that could even live one level higher: ```Javascript { "clickRoutine": [ { "func": "COUNT" }, "w.widgetID1.height = w.widgetID2.height + v.var1 + v.var2", { "func": "COUNT" } ] } ``` That would set property `height` of the widget with `"id": "widgetID1"` to property `height` of the widget with `"id": "widgetID2"` plus variables `var1` and `var2`. I would make this really restrictive though to avoid complexity and `eval`. Left hand only `v.*` or `w.*` and right hand the same plus basic math operations (`+-*/` and boolean logic pretty much). Numeric literals would also be fine. Maybe even strings. And probably `w[v.var1].height` so you could use variables as widget IDs.
Author
Owner

@robartsd commented on GitHub (Jan 27, 2021):

Maybe even strings.
Validating safe strings can get pretty tricky.

I like adding it to applyVariables. It would finally justify why applyVariables isn't just {"parameter1":"variable1"} . I'd name it "template" rather than "literal".

@robartsd commented on GitHub (Jan 27, 2021): > Maybe even strings. Validating safe strings can get pretty tricky. I like adding it to `applyVariables`. It would finally justify why `applyVariables` isn't just `{"parameter1":"variable1"}` . I'd name it "template" rather than "literal".
Author
Owner

@larkob commented on GitHub (Jan 27, 2021):

Ah, I see my fault. Template literals have to be written directly in the JS code and cannot be declared in JSON - or they would have to be eval'd.

@larkob commented on GitHub (Jan 27, 2021): Ah, I see my fault. Template literals have to be written directly in the JS code and cannot be declared in JSON - or they would have to be eval'd.
Author
Owner

@larkob commented on GitHub (Jan 27, 2021):

I've figured out an alternative approach that's almost as good as using template literals. It would only allow the use of variables, no mathematical expressions or if/else conditions, but I think it's quite useful on its own:

{
"func": "LABEL",
"label": "<labelId>",
"applyTemplate" [{
  "template": "Amount: {COUNT}",
  "parameter": "text"
}]
}

It would also allow access to any widget's properties without an extra GET operation, so it'd be quite useful in a COMPUTE:

{
"func": "COMPUTE",
"operation": "-",
"applyProperty" [
{
  "property": "myWidgetID.height",
  "parameter": "operand1"
},{
  "property": "myOtherWidgetID.height",
  "parameter": "operand2"
}
]
}

I don't want to go into the technical details of how this is going to work, but I am confident enough to try to code this.

@larkob commented on GitHub (Jan 27, 2021): I've figured out an alternative approach that's almost as good as using template literals. It would only allow the use of variables, no mathematical expressions or if/else conditions, but I think it's quite useful on its own: ``` { "func": "LABEL", "label": "<labelId>", "applyTemplate" [{ "template": "Amount: {COUNT}", "parameter": "text" }] } ``` It would also allow access to any widget's properties without an extra GET operation, so it'd be quite useful in a COMPUTE: ``` { "func": "COMPUTE", "operation": "-", "applyProperty" [ { "property": "myWidgetID.height", "parameter": "operand1" },{ "property": "myOtherWidgetID.height", "parameter": "operand2" } ] } ``` I don't want to go into the technical details of how this is going to work, but I am confident enough to try to code this.
Author
Owner

@robartsd commented on GitHub (Jan 27, 2021):

Could we make all this part of a single dynamic property array?

"applyVariables" [
{"parameter":"parameter1","variable":"myVariable"},
{"parameter":"parameter2","property":"myWidgetID.property"}
{"parameter":"parameter3","template":"{playerName} Amount: {COUNT}"}
]

Perhaps a different name might be appropriate, but I dislike having to provide an array of objects each object only having two properties - providing an object with key:value pairs would make more sense if we aren't going to use more than two properties in the object.

@robartsd commented on GitHub (Jan 27, 2021): Could we make all this part of a single dynamic property array? ``` "applyVariables" [ {"parameter":"parameter1","variable":"myVariable"}, {"parameter":"parameter2","property":"myWidgetID.property"} {"parameter":"parameter3","template":"{playerName} Amount: {COUNT}"} ] ``` Perhaps a different name might be appropriate, but I dislike having to provide an array of objects each object only having two properties - providing an object with key:value pairs would make more sense if we aren't going to use more than two properties in the object.
Author
Owner

@robartsd commented on GitHub (Jan 28, 2021):

@larkob's idea is great and templating basically solves the original for strings. It would still be nice to have as many operands as you want for several operations. I'd propose an operandCount property and setting default operands and operand count per operation.

Operations where this seems like it would be useful:

  • +
  • &&
  • ||
  • max
  • min
  • concat (solved by @larkob's template proposal but included for completeness)
  • concatArray
  • arrayOf (not currently implemented, but would be very useful for creating arrays if we added operandCount)
@robartsd commented on GitHub (Jan 28, 2021): @larkob's idea is great and templating basically solves the original for strings. It would still be nice to have as many operands as you want for several operations. I'd propose an operandCount property and setting default operands and operand count per operation. Operations where this seems like it would be useful: - `+` - `&&` - `||` - `max` - `min` - `concat` (solved by @larkob's template proposal but included for completeness) - `concatArray` - `arrayOf` (not currently implemented, but would be very useful for creating arrays if we added operandCount)
Author
Owner

@rogerl50 commented on GitHub (Jan 28, 2021):

Another possibility (or perhaps in addition) would be to allow COMPUTE to accept an array of operations, something like:

{ "func": "COMPUTE", 
  [
  {  "operation": "+",
   ...
   "variable": "foo" },
  { "operation": "*",
    "applyVariables": [ {"parameter" : "operand1", "variable" : "foo"}],
   ...
  }
  ]
}

First off, this isn't valid JSON (no key for the array). It also wouldn't do much to reduce the length of code needed to accomplish multiple "COMPUTE" steps.

@rogerl50 commented on GitHub (Jan 28, 2021): Another possibility (or perhaps in addition) would be to allow `COMPUTE` to accept an array of operations, something like: ```JSON { "func": "COMPUTE", [ { "operation": "+", ... "variable": "foo" }, { "operation": "*", "applyVariables": [ {"parameter" : "operand1", "variable" : "foo"}], ... } ] } ``` First off, this isn't valid JSON (no key for the array). It also wouldn't do much to reduce the length of code needed to accomplish multiple "COMPUTE" steps.
Author
Owner

@larkob commented on GitHub (Jan 29, 2021):

I've created PR #180 for using templates and properties in applyVariables. Although it resolves the original use case, this still does NOT allow to use multiple operands with COMPUTE, so I'll leave this issue open for now.

@larkob commented on GitHub (Jan 29, 2021): I've created PR #180 for using templates and properties in applyVariables. Although it resolves the original use case, this still does NOT allow to use multiple operands with COMPUTE, so I'll leave this issue open for now.
Author
Owner

@ArnoldSmith86 commented on GitHub (May 21, 2021):

We didn't exactly implement this but I feel like #307 solves this problem.

If you still really need something better, please re-open the issue.

@ArnoldSmith86 commented on GitHub (May 21, 2021): We didn't _exactly_ implement this but I feel like #307 solves this problem. If you still really _need_ something better, please re-open the issue.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/virtualtabletop#89
No description provided.