C# - Object params passed by reference(?) not being updated - why? [Solved]

Why are the objects of one list (geolist) being updated (transformed) but not the other (ptlist)? See code below. In short, the points (pt0, pt1, pt2) are not transformed while the geometry objects are.

I have tried to pass both lists as “ref” to tyhe TransformStuff method, but the points are not modifed.

In any case, I expect objects in a list to be a list of object referenced, and thus modified also in the calling method scope. Coming from Delphi/Pascal I’ve never seen anything like this before. in pascal any object passed around really is a reference to an object, period. But here I can’t even guess what’s happening.

What am I doing wrong? < puzzled >

{
    ...
    var ptlist = new List<Point3d> { pt0, pt1, pt2 };
    var trf = Rhino.Geometry.Transform.Rotation(vec1, vec2, center);
    TransformStuff(trf, geolist, ref ptlist);  // <-- points not modified when I use them hereafter
    ...
}

private void TransformStuff(Rhino.Geometry.Transform trf, List<GeometryBase> geolist, ref List<Point3d> ptlist)
{
    // points to be rotated
    if (ptlist != null)
    {
        for (var i = 0; i < ptlist.Count; i++)
        {
            if (ptlist[i] != Point3d.Unset)
                ptlist[i].Transform(trf);
        }
    }

    // geometry to be rotated
    if (geolist != null)
    {
        for (var i = 0; i < geolist.Count;i++)
        {
            geolist[i].Transform(trf);
        }
    }
}

// Rolf

Hm, A Point3d is not full a citizen object, it’s only a struct. And thus Structs can’t be passed around in lists or arrays as references by no means (?)

So, in the form of lists/arrays, they allways must be returned from other methods by value only(?), unless being passed individually as ref variables.

Is the above correct, with no peep holes to creep through?

GC is evil.

// Rolf

Rolf, have you tried something like this ?

 Point3d p = ptlist[i];
 p.Transform(trf);
 ptlist[i] = p;

… just guessing
my C# is very rusty … sorry

Hi @emilio

I actually had the opposite problem, a number of local variables, which I didn’t want to send as individual method parameters, so I put then into an array instead, like so:

// my local vars into an array    
var ptlist = new Point3d[3] { ptHRC, ptHRRef, ptGRRef };

// transform
RotateAboutXAxis(trx, geolist, ptlist);

// update concerned local variables
ptHRC = ptlist[0];
ptHRRef = ptlist[1];
ptGRRef = ptlist[2];

But the problem is essentially the same as that you describe, in that the local vars has to be updated explicitly, since they are not (cannot?) by passed “by reference” (as referenced array or list elements)

This of course invites every possible bug to creep in when maintaining the code… :sunglasses:

// Rolf

Hmmm … what about using Point objects ?

http://developer.rhino3d.com/api/RhinoCommonWin/html/T_Rhino_Geometry_Point.htm

1 Like

What? I didn’t know that. :+1:

Now that actually solves the basic problem I wanted to solve. Thanks!

// Rolf

This is a vital fact about C# (and VB.NET). There are two types of objects; value types and reference types. Uuuusually value types tend to be small (just a few bytes) and fixed in size whereas reference types tend to be the more complicated kind of data.

In C# these two kinds are called ‘structs’ and ‘classes’ respectively. When you pass structs into a function, or store them in some variable the entire value is copied. Whereas if you pass classes to a function or a local variable, you get a new reference to the same memory.

Thus, imagine the following code, assuming a class of type Data:

Data data = new Data(5);
Data data2 = data;
data2.Value = 6;

At the end of that code data.Value will be 6, because both data and data2 reference the same memory address.

If however Data were a struct, then the second line would create a copy of data, and the state of data would not be modified when data2 is messed with.

Typical examples of structs in the core framework are System.Double, System.Boolean, System.Int64 (or double, bool, and long as they are known in C#). Typical examples of structs in RhinoCommon are Point3d, Plane, Line, Circle, Transform)

Yes David,

I guess allowing the following syntax tempts me to forget that Vector3d and Point3d are Value types :

var pt = new Point3d();

To a Delphi/Pascal oldtimer like me, which is forever stuck in endless loops playing with pointer based linked lists in sleep, this “new” clause is confusing. It looks like “allocate a pointer”.

Again, GC is evil. :slight_smile:

// Rolf

Yeah, that should be a compiler warning in my opinion.

< DUMB OLD SCRIPTER’S OPINION >
Hehe … but useful at a quick-and-dirty level … say for scripts, no ? :smile:

And what about OOP ?
Actually it keeps looking somehow weird to me … :confused:
< / DUMB OLD SCRIPTER’S OPINION >

Anyway, FWIW, when scripting in Python, the problem with RhinoCommon objects is the opposite.
Since Python has no structs, all those things (Point3d etc.) are real objects, which is fine.
But sometimes you have to duplicate some of them and obviously (Since they are originally structs) there is no Duplicate() method for them in RC …
So you find yourself hunting for ways to duplicate that stupid thing … :smile:

Regards

Haha. Guess what? The new Google Language (Go/Golang) doesn’t implement Object Orientation (classes) only Structs and Interfaces. And one of the lead designers of Go is an old Delphi guy immersed in OOP, Robert Griesemer. It’s like he started swearing in church sort of.

Although I understand their rationale for this strategy, I do have a problem with the endless repeating of similar code due to the lack of inheritance and polymorphism. But they say only that I’m thinking OOP using a non-OOP language so I can only blame myself,

I guess traditional OOP destroys something in your brain. Makes you lazy, or something. :slight_smile:

But GC makes you even lazier, and… Ah, never mind.

(Just joking, I’m fine with GC by now. As I grow older I feel less end less need for doing all the hard work… :upside_down_face: )

The right tool for the right job is key. And the most efficient programming language is the language you have spent time to master.

I blame GC instead of blaming myself. Scapegoat. GC probably isn’t the big problem out there, after all. :slight_smile:

// Rolf

I don’t know Griesemer … but do know the other two guys ( Bell Labs … Unix … etc.)
I’ll have to look more closely at Go, thanks ! :slight_smile:

And laziness might not be so bad after all … http://threevirtues.com/ … Hahaha.

Yes

Thank you

Which doesn’t mean you shouldn’t try mastering languages you haven’t used yet. It is especially useful to learn languages with paradigms you are currently unfamiliar with. New ways of thinking will give you many new insights in the languages you already have mastered. Learning and improving never stops.

2 Likes