kentor
kentor

Reputation: 18534

Increment variable from methods

I would like to increment a counter in a method, like this:

  row(title, height):: {
    _panels:: [],
    _panelSlot:: 0,

    addPanel(panel):: self {
      self._panelSlot = self._panelSlot + 1,
      _panels+: [{
          slot: panelSlot,
          panel: panel,
      }],
    },

The line self._panelSlot = self._panelSlot +1 is what I have expected to work, however that does cause the following error:

STATIC ERROR: lib/grafana/builder.libsonnet:157:7-11: unexpected: self while parsing field definition

My second try:

I'm unsure whether this would overwrite the _panelSlot variable, but I couldn't confirm because I failed to access that variable on my object array:

  row(title, height):: {
    _panels:: [],
    // height is the row's height in grid numbers and it is used' to calculate the 
    // panel's height and y pos accordingly.
    _height:: height,
    // panelSlot is the row panels' current position from left-to-right. If there are
    // two or more stacked panels they share the same slot. This is used to calculate
    // the width for each panel.
    _panelSlot:: 0,

    addPanel(panel):: self {
      local parent = self,
      _panelSlot:: self._panelSlot + 1,
      _panels+: [{
          slot: parent._panelSlot,
          panel: panel,
      }],
    },
RUNTIME ERROR: max stack frames exceeded.
...
<anonymous>
        lib/grafana/builder.libsonnet:(13:9)-(15:10)    thunk <array_element>
        lib/grafana/builder.libsonnet:19:29-35  object <anonymous>
        lib/grafana/builder.libsonnet:19:15-37  thunk <array_element>
        lib/grafana/builder.libsonnet:(7:24)-(20:6)     object <anonymous>
        During manifestation

My question

How can I modify variables (i.e. increment a counter) within a method, so that the modified variable is accessible in the next call of that method?

Upvotes: 0

Views: 872

Answers (1)

jjo
jjo

Reputation: 3020

How can I modify variables (i.e. increment a counter) within a method, so that the modified variable is accessible in the next call of that method?

IIUC you can't really keep and mutate state in a way similar to other OOP languages.

You can approach this by mutating an object into a new one (with the modified/added data) by chaining calls that return the new object

Example1

Crafting an example below:

Code:

local Array = {
  array: [],
  count: 0,

  addElem(e):: self {
    // Overload (mutate) this object
    array+: [e],
    count+: 1,
  },  // return mutated object
};

// Below 4 lines are equal to
// Array.addElem('x').addElem('y').addElem('z'); but kinda more readable
local obj = Array
            .addElem('x')
            .addElem('y')
            .addElem('z');

obj

Output:

$ jsonnet example1.jsonnet
{
   "array": [
      "x",
      "y",
      "z"
   ],
   "count": 3
}

Example2

Applying above approach to your code:

Code:

local Class = {

  Row(title, height):: {
    local this = self,  // clamp a reference to the current self

    _panelSlot: 0,
    _panels: [],
    _height: height,

    title: title,

    // addPanel() changes it-`self` to return a mutated Row
    addPanel(panel):: self {
      _panelSlot+: 1,
      _panels+: [{
        slot: this._panelSlot,
        panel: panel,
      }],
    },
  },
};

local obj = Class
            .Row('Title', 42)
            .addPanel('Foo')
            .addPanel('Bar');

obj

Output:

$ jsonnet example2.jsonnet
{
   "_height": 42,
   "_panelSlot": 2,
   "_panels": [
      {
         "panel": "Foo",
         "slot": 0
      },
      {
         "panel": "Bar",
         "slot": 1
      }
   ],
   "title": "Title"
}

BTW would recommend taking a look at grafonnet-lib in case you didn't already.

Upvotes: 1

Related Questions