Grasshopper has evolved somewhat since its beginnings and it's becoming increasingly common to find Grasshopper developers out there looking to push the boundaries of visual programming/modelling. For the most part, scripting for Grasshopper was done within the built-in scripting components (for Python, C#, etc). It allows people with little programming knowledge to create their custom Grasshopper logic quickly. And there are forums available to discuss options on, or find helpful code/hints.
With a new knowledge base, there has been a movement towards the use of compiled components. These components, still written in C#, allow programmers to create entirely custom calculations. Some do massive amounts of calculations in one component with loads of options available. This goes against the original Grasshopper ethos, but while it's here to stay, it seems it might be good to discuss code re-usability within compiled components.
James pointed me in the direction of this discussion on the Grasshopper forums relating to the possibility of calling Grasshopper functions from other tools. It's an interesting question, and a perfectly valid one. There are many components available within Grasshopper that contain functions that would be useful in other components. All too often we end up with components taking a large number of inputs to try to obtain calculated data from other sources. Which is great - this follows the Grasshopper ethos of little components doing little parts of a task that build into a bigger task.
But is it possible to call Grasshopper functions from other components and have them work correctly? Providing to follow some sense of proper programming practice then yes, it's certainly possible. Hopefully this post will give some tips on how to make your Grasshopper compiled code more re-usable for yourself, and fellow Grasshopper users.
Separation of Concerns
The separation of concerns design principle is core to increasing the re-usability of code. The design principle prevents code from becoming too entangled with itself that it becomes impossible to separate GUI from core code. So how does this apply to Grasshopper components?
When you first make a Grasshopper component in Visual Studio, you're given a framework which contains the core methods which you need to fill in to make your component work, such as the inputs, outputs and 'solve instance'. It's brilliant in its simplicity - you just provide the input manager with what input parameters you want, provide the output manager what outputs you're giving, and calculate the difference in 'solve instance'. But this is where re-usability of components begins to fall down. The 'solve instance' isn't easily accessible outside of the Grasshopper document/canvas (James has a post trying it - he ends up creating a dummy Grasshopper document to work with). By tying up your calculations within 'solve instance', you've instantly failed the separation of concerns principle.
The framework you're given for a component is the GUI. It provides the interactions between the calculations (core code) and the user (GUI) who will play about with the component on the canvas. So if you want to make your code more re-usable, stop putting calculations in 'solve instance' - separate out the GUI from the core code. Use the 'solve instance' to do one thing - take in your inputs, pass them along to your calculations, then take the results and pass them back to user. Nothing else.
Don't use global variables
Global variables are nice, you don't have to worry about their scope or not being able to access them because everything in that class can access them. It's a wonderful thing right? Until you want to reuse something and can't get the global variables quite right because they're locked away inside inaccessible code.
If you must use global variables (and sometimes this does happen - there are legitimate reasons for using global variables) then make sure you have some getter/setter methods (where appropriate) so the variables can be accessed, read and modified from external code sources. Never give access to a global variable directly (always keep them private), but provide controlled access with proper getter/setter methods.
But if you can avoid them, then do. It'll give the person re-using your code (which may be you) easier access to your calculation methods. Instead, keep variables localised to the functions which need them at the time and pass them as arguments to later functions.
Have separate 'calculate' methods
So you want to separate your core code from the GUI, this means you're going to need some methods which perform the calculations for you. There's nothing fancy with these, they're simply methods which take in some input parameters (or use global variables if you really couldn't avoid it) and returns some output. The example below shows a method adding two numbers together - it's simple but it quickly demonstrates the point being made.
public int CalculateNums(int a, int b)
int result = a + b;
Make your calculation methods public and other tools trying to call them will be able to do so. Don't make them static - you don't have to, and this may impair the performance of your original component. Simply having it as a public method will be fine.
How can we use that in other components?
Let's pretend we have a perfect Grasshopper component - one where 'solve instance' simply takes in some inputs, passes them along to a calculation and returns some outputs. Now let's pretend we want to use those calculations in another component, but we don't want to re-write them because they're long and might not work if you simply copy/paste them.
If we've followed the guidelines outlined in this post, we can do something like this:
private void MyMethod()
var someData = myData;
var moreData = alsoMyData;
MyComponent mc = new MyComponent(); //Creating an instance of the object component - that's all components are, an object in the Grasshopper world
var results = mc.Calculate(someData, moreData); //Use the calculation method in MyComponent to calculate the results on this data.
In conclusion - there are ways in which you can access functions which reside within other Grasshopper components by simply making an instantiation of the component object within your code and treating it as a normal object in code space. But if you want to get something meaningful out of it, you need to access calculation methods that are separate from the 'solve instance' to prevent the need to 'use' a Grasshopper document as James had to.
If everyone built compiled components following standard programming principles, it would be very easy to reuse code without re-writing it every time. Of course, this would also make it easy for others to reuse it but there are other ways to protect against that with licencing and 'safe DLLs' but that's a discussion for another time.
One final note though - scripting in Grasshopper was made to be easy. So if you're doing something simple, don't over complicate it with a compiled component if a quick scripted one will do. Remember, you can save scripted components so that they become reusable as well. But if you do venture into the land of compiled components heed the advice in this post - it might save future you some headaches...