Problems in a simple for loop C#

Hi all,

I am trying to move points in a simple for loop but for some reason it does not work.
If I use the same methode without loop it works.
It has to be a silly error I do, I just cant see it.

Thanks for any hint!
20191130_PtsMove.gh (3.5 KB)

You don’t need to construct a transform that way if it’s not something you will be reusing. You could do

pts[i].Transform(Transform.Translation(vectors[i]));

Yes, I thought that.
Unfortunately it does not solve my problem.
I don’t have any clue why it does not work.

I believe you will need to make a copy of the point first as well. Usually you will want to transform copies of geometry. Make a new point3d list newPts

Point 3d newPt = new Point3d(Pts[i]);
newPt.Transform(Transform.Translation(vectors[i]));
newPts.Add(newPt);

1 Like

Ok, that works.
Thanks a lot Michael.
I tried it before but forgot to aassign the new points to the output :man_facepalming:

1 Like

Hi Baris,

I think there is a much more efficient way to translate points.

You have a few redundancies with what you are doing:

  1. For every vector you create a new Transform struct even though you already have a vectors as inputs.
  2. You have to create another List to store the translated points to be able to output them, even though your input is already a list of points…

Imagine if you are dealing with thousands or millions of points and vectors, this will be a huge amount of unnecessary memory usage

if you just do this, it will work:

for (int i = 0; i < pts.Count; i++)
    {
      pts[i] += vecs[i];
    }
        
    A = pts;

So any class, interface, dynamic, and delegate in C# is a reference type this means that they contain a “pointer” to a another memory location in your computer. What this basically means is that when you assign a copy of a class to a variable and you modify the newly created variable you will end up modifying the values of both objects.

// Lets say we have a class named Foo

public class Foo
{
    public int value;
    public Foo(int val)
    {
       value = val;
    }


}

// lets assume this is our main program

Foo a = new Foo(2);

// We create a new Foo object and we assign the previous object to it
// b points to the same memory address of a
// in essence they are the same thing
Foo b = a;

b.value = 5;

// if we would check the results of this

Print(a.value.ToString();

Print(b.value.ToString();

// we would get 5 for both objects. this is because both variables point to the same address in memory

// 5
// 5


Structs are the opposite, they contain the address of where they are located in memory not a reference to it. So if you try to copy a struct in a new variable what is actually happening is that an independent memory address is created to store that variable This causes that any change that you do on this copied version will not affect your original object because you are not operating on the same data any longer.

// lets take a known struct as an example

Point3d p1 = new Point3d(0,0,0);

// p2 now has an independent memory address
// making it different than p1
Point3d p2 = p1;

p2.X = 10;

// check the results

Print(p1.ToString());

Print(p2.ToStrint());

//ouputs will be

0
10


Structs also become copied when are passed in to methods


public void Test( int num)
{
	
	num+=1;
}

// Main program

    int a = 10;
    Test(a);
    Print(a.ToString());

// output

10

But if they are passed in a method with a little keyword named ref they will get passed as a reference type

public void Test( ref int num)
{
	
	num+=1;
}

// Main program

    int a = 10;
    Test(a);
    Print(a.ToString());

// output

11

So this

for (int i = 0; i < pts.Count; i++)
    {
      pts[i] += vecs[i];
    }
        
    A = pts;

works because you are operating on a List which is defined as a class in C# (meaning a reference type) So when you are modifying all the elements in the list you are changing the data itself not a copy.

As an exercise, you can create a struct and define one of its properties to be a reference type. Then create an instance of the struct and assign that instance to another variable. After this, try changing the value of the reference type property, what do you think will happen?

6 Likes

Silly me, dunno why I overlooked to mention that you can do points plus vectors. Got caught up in literal fixing of the posted code about translation. Thanks for adding!

It can always happen :sunglasses:

1 Like

Hi Nicholas,

thanks a lot for the detailed explanation!Really apreciated.
It’s nice that such a small and basic question can lead to learn/understand so many things.
For sure I’ll do the excercise you put at the end, I’ll come back to this later today.

Regards!

No worries, It is quite an abstract thing to get your head wrapped around, there is much much more to it which I also want to learn more about. The idea of things referencing to other memory locations is quite an abstract idea to imagine. Apparently, when data is stored in the “heap” memory of your computer it can be stored all over that place. That is why in most cases people say that classes have slightly less performance than structs, but of course it all depends.

But it is a very important topic to understand when programming and it becomes a challenge to keep it present while you are hacking away at something. Sometimes I have made very silly mistakes and then it is a good moment to laugh at myself once I discovered my self induced bug.

In your first example, Not only in each iteration of the loop the computer was storing that Transform struct in the “stack” memory of your computer, but also all your vectors where being stored as copies (reason why the translation was unsuccessful) and also a List was being created , though stored in the heap… Of course for that simple example it does not mater much. but imagine the harm in can cause in performance if the computer had to allocate so much memory doing that for hundreds of thousands of items.

A a general thing to also note is that these so called “pointers” are also a type of variable but these guys are always stored in the stack. So when you create an instance of a class

Foo f = new Foo();

What is happening is that the variable f is actually a pointer that is saved on the stack and as it name suggests, it is pointing to or referencing to the memory address of the object Foo in the heap. So essentially Foo lives on the heap and its pointer on the stack. This is why when you create a new variable and store Foo in there

Foo f = new Foo();

Foo f2 = f;

Although f and f2 are stored in unique memory locations in the stack, the pointer f2 is also pointing to the same memory location where Foo is stored. But remember its pointing to a different area in memory which is the heap. So whatever you do to either variable it will change both.

Things can get a little messier when you do things like passing a class by reference in a method.
say you have

public class Animal
  {
  }

 public class Human: Animal
  {
  }

 public class Tiger : Animal
  {

  }

  public void Change (ref Animal h)

  {
     h = new Tiger();
  }
  



//////// MAIN////////

Animal a= new Human();


Change(ref a);

Print(a.GetType().ToString());

/// the variable a will no be a Tiger!

So when the code is running, first the a variable will go on the stack and then the Human object on the heap. when calling the Change() method the variable h will be stored on the stack and it will point to a. Then the Tiger object goes to the heap and finally the value of a is changed by h to the memory address of the Tiger object. This is why if we print the type of a it will be a Tiger and not a Human

Long story short… all this stuff can be confusing :sunglasses:

1 Like

Hey,
thanks again Nicholas, so much to study :exploding_head:
I am still experimenting with the first example(we are in the last days of a project, so nearly no sparetime).
The second one seems to be way more advanced but I am taking the oportunity and do the challenge.

Regards from Monterrey

Just a hint, even though in essence structs are allocated in the stack, if it contains a property that is a reference type, its pointer will be allocated in the stack but the actual object in the heap

Memory management is a bit more complicated in .NET than a simple stack/heap choice. But yeah, in general it’s good advice to not have structs with pointers in them. You need a really good reason to break that guideline. There are good reasons though, and there’s even examples in the .NET framework of this happening (for example CancellationToken).

An even more important struct design guideline is immutability. And sadly there’s lots of counter examples (in .NET and RhinoCommon), but there’s never a good reason to break this rule.

Yeah actually I think that reading C++ stuff on memory management makes things “clearer” depending on the level you want to take it.

https://openframeworks.cc/ofBook/chapters/memory.html

although of course it can get very complex, because C++ lets you do things that C# does not, as you probably know much better then me.

So why is Vector3d not immutable in RhinoCommon, is there a good reason? Actually yesterday I came through .NET’s System.Numerics namespace which apparently contains some Vector structs that are immutable and described to be very powerful computationally.

I actually did a quick test yesterday. I created two Vector<T> each with 1 million elements and computed the dot product between them and the time it took was 0 milliseconds!

They seem to support something called SIMD “executing a Single Instruction in Multiple Data, so parallelism occurs in a single core” which I dont really know exactly what that means yet.

It was written in the early days of .NET, I’m not sure how many guide-lines any of us had read at the time. Also, very similar structs (e.g. System.Drawing.PointF, System.Drawing.RectangleF, etc.) were also mutable.

I’m well into my second decade as a professional programmer, but I’ve only really learned about the importance of pure functions, immutable types, and test-driven development embarrassingly recently. Luckily not everyone at McNeel is as uninformed as me

Well… lol I still think to do the initial release of Grasshopper all by yourself was very impressive, huge admirassion from my side David, how long did it take you to deploy the first release? and how long did you begin to program before joining McNeel?