Peristent Data is available to other instance of the same component

Hi,
I am relatively new in grasshopper development. I was developing a component with persistent data and realised that if I instantiate another componet with the similar inputs the default output value from the new component is taken from the old component.
Let me illustrate with an example.
I have created a component where it computes a simple addition of two numbers when a button is clicked ; also it resets the value if a reset button is clicked. but once the data is computed, and I put another component (red group) in the canvas and fed in all the input parameter by default it shows the value from th previous compoent ( white group).
What steps can be taken to avoid this scenario ? I want to instantiate multiple similar component without this problem / issue.

This is the code I have used for the component

using Grasshopper;
using Grasshopper.Kernel;
using Rhino.Geometry;
using System;
using System.Collections.Generic;

namespace PersistentData
{
    public class PersistentDataComponent : GH_Component
    {
        private static double _addition; // persistent variable to store addition
        /// <summary>
        /// Each implementation of GH_Component must provide a public 
        /// constructor without any arguments.
        /// Category represents the Tab in which the component will appear, 
        /// Subcategory the panel. If you use non-existing tab or panel names, 
        /// new tabs/panels will automatically be created.
        /// </summary>
        public PersistentDataComponent()
          : base("PersistentData", "PD",
            "This components adds and clears two numbers on command",
            "AD_TEST", "Core")
        {
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
        {
            pManager.AddBooleanParameter("Reset", "R", "Reset the Addition", GH_ParamAccess.item);
            pManager.AddBooleanParameter("Compute", "C", "Compute the Addition", GH_ParamAccess.item);
            pManager.AddNumberParameter("A", "A", "Component A", GH_ParamAccess.item);
            pManager.AddNumberParameter("B", "B", "Component B", GH_ParamAccess.item);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
        {
            pManager.AddNumberParameter("Result", "R", "Addition Result", GH_ParamAccess.item);
        }

        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object can be used to retrieve data from input parameters and 
        /// to store data in output parameters.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            bool reset = false;
            bool compute = false;
            double a = double.NaN;
            double b = double.NaN;

            DA.GetData(0, ref reset);
            DA.GetData(1, ref compute);
            DA.GetData(2, ref a);
            DA.GetData(3, ref b);

            if (reset)
            {
                _addition = 0;
            }

            if (compute)
            {
                _addition = a + b;
            }

            DA.SetData(0, _addition);

        }

        /// <summary>
        /// Provides an Icon for every component that will be visible in the User Interface.
        /// Icons need to be 24x24 pixels.
        /// You can add image files to your project resources and access them like this:
        /// return Resources.IconForThisComponent;
        /// </summary>
        protected override System.Drawing.Bitmap Icon => null;

        /// <summary>
        /// Each component must have a unique Guid to identify it. 
        /// It is vital this Guid doesn't change otherwise old ghx files 
        /// that use the old ID will partially fail during loading.
        /// </summary>
        public override Guid ComponentGuid => new Guid("04F9D727-C988-412E-B045-27A65A89D957");
    }
}

Hi @adas

This is because you are using a static variable. _addition is shared between all class instances of your component. If something static If you remove the static keyword, the variable will become “persistent” locally to each class instance. In short a static variable is shared among all instances of the class.

Generally speaking is not recommended to use static code because it creates tight coupling, lends to violate the single responsibility principle in classes and also diminishes the intent of your code as well as other horrible stuff if you are not careful. For example the famous “Util” class which is always made static generally has a bunch of random methods thrown inside and the class becomes ambiguous just as its name.

This is not to say that you should never use static code, you just need to know why and when you should use it. A classical design pattern for static classes is called the Singleton design pattern. You can use it when your app only needs a single instance of that class during its life time and when its data will be stateless (static) during the duration of the program.

1 Like

@rawitscher-torres ,

Thank you for your generous explanation. I will take the suggestion and redesign it.

Thanks
Avishek