algorithmic modeling for Rhino

Hello forum,

I seek some knowledge about what is going on in the Grasshopper components.

Does DA.GetData() (or DA.GetDataList() or DA.GetDataTree()) reference an existing object or does it create a local copy of the input?

Say I need to pass an object around in different components but need to have only one instance of that class, since clones or copies will crash my program.


Views: 142

Reply to This

Replies to This Discussion


usually classes, compared to structs or primitive datatypes, are always passed by reference. However Grasshopper needs to copy them, because otherwise you couldn't have two different states of an class instance being existent at the same time. (You can see any components state at everytime, you can bake etc...)

The duplication of those objects which are classes within Rhino.Geometry, usally works really fast, and can be ignored under normal circumstances. However, what you can do is passing a fake reference (as long you are not wanting to deal with C# in "unsafe mode" and sharing real pointers, which is indeed very unsafe). So what you could do instead is passing an index, a guid, or another type of unique id and only retrieve the instance from a list or dictionary, being around from the moment on when grasshopper is loaded. So that if you create this instance, you simple add it to the list and if you like to modify it, you only access the list at the right location.

Thanks a lot Tom!

I see, that was my assumption. I was thinking about passing pointers as well, but since myClass is a reference type I can not use pointers in C# (apparently C# only supports pointers for value types and structs of such).

Your idea of making a sort of custom pointer is very good, I'll try that.

Thanks again! Cheers

If you ask for the IGH_Goo type, then you always get the original data:

GH_Brep brep = null;

if (!DA.GetData(0, ref brep)) return;

No copying. If you ask for a derived type, then it depends on how the conversion is defined. For almost all (I'd say all, but I can't remember for sure) native types this is also done without copying. I.e.:

Brep brep = null;

if (!DA.GetData(0, ref brep)) return;

also gives you a reference to the actual brep that is inside the GH_Brep instance, again no copying.

When you use VB/C# script components, then you always get a safe instance you can change. I did this because I figured scripters would be less savvy than VS developers about making sure data is copied whenever necessary.

When making a GHA, and you want to modify the data in the input, you must always make a copy yourself. It's the only way to be sure.

Hello David,

thanks a lot for the reply. And for custom classes I'd use GH_ObjectWrapper??
I'm thinking of something like:

GH_ObjectWrapper obj= null;

if (!DA.GetData(0, ref obj)) return;

MyClass mc = (MyClass)obj.Value; point me to the original instance?


"When making a GHA, and you want to modify the data in the input, you must always make a copy yourself. It's the only way to be sure."

I don't want to change the data of myClass downstream, I just want to retrieve information from it. Is that save?

GH_ObjectWrapper is a last resort type which is used to encapsulate data for which no suitable IGH_Goo implementation can be found. GH_ObjectWrappers do not know how to do anything with the data they contain (read it, write it, copy it, transform it, ...) so it will definitely not copy the values.

The major downside of using GH_ObjectWrapper is that it will probably fail to be written to a gh file in case it is internalised in any parameter.

Okay so for custom classes my best bet would be Tom's suggestion to link and refer to my instance in the global document scope, correct?

Oh okay, I was wrong here. I never was in need of creating an own parameter object types contracted from the interface IGH_Goo. I also always retrieved information from my input and implement my own datatypes, so I never come into the situation of directly modifying my input data. My assumption came from the script components where I tested it before replying, and I measured a relative high timespan ,which must come from the conversion process. But if script components work differently, I understand now why. Good to know though. Thank you David

Sorry I made a different mistake here:

My problem was that in the second component I initialized another instance of myClass before assigning it. Like this:

MyClass instance = new MyClass();

DA.GetData(0, ref instance);

..this instance created internal problems, since i shouldn't initialize two instances.
It works when I set it to null instead:

MyClass instance = null;
DA.GetData(0, ref instance);

That was wrong thinking from my side. Maybe someone will find this text useful some day.






© 2018   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service