Search code examples
c#lazarusfreepascal

Lazarus pointer type in C#


I am trying to convert a lazarus project to c#. It's been good so far but i have a problem now.

There is a code like this:

    xActor = record
    Id: integer;
    Value: integer;
    Name: ansistring;
    Height: integer;
    Gender : Boolean;
    Position : byte;
  end; 

I created this in c# as a struct. However, after this code i saw something like this

PxActor = ^xActor;

I've researched a bit and found out that this means create a type that includes xActor's pointers i may be wrong tho.

Then i saw a more interesting record in the code

    yActor = packed record 
    Actor: array [1..9] of PxActor;
  end;

at this point i have no idea how to convert these to c# since i have no idea what PxActor = ^xActor; means.

Thanks in advance


Solution

  • C# has two different kinds of an object - a reference-type, and a value-type.

    The code you have is mixing the two (very common in C/Pascal), because you have a C# value-type (the struct xActor) and a reference-type referring to the same type (the pointer PxActor), which isn't quite possible in C#.

    However, there are ways to emulate similar behaviour. But first, you have to think about the logical way this is supposed to work. Maybe this is just a performance tweak (e.g. the array of PxActor is used instead of xActor because you want to save up on the extra memory from having the whole xActor structure there). Perhaps it's rather that you want to have the same value available from multiple places, and mutable.

    Both cases can usually be solved by simply making xActor a class - in C#, that means that it will always be a reference type (not something that makes sense in C/Pascal, but the predominant object in C# and similar languages). However, you need to manually check every place where anything of type xActor or PxActor is used, and make sure the value/reference semantics are still the same. This can lead to some hard to find bugs, depending on the original code.

    Another option is to create a wrapper class. So you'll keep your struct xActor, but you'll also create a class PxActor, which will have a single xActor field. This is not an exact analogue of Pascal's pointers, but if you're careful, it can be used in a similar way. The main difference is that you can't capture a pointer to an existing value somewhere - you can only create a new PxActor, with it's own copy of xActor. Anyone accessing the PxActor instance will also be working with the same xActor instance, but anytime you store the xActor itself, it's a new copy. But in the simplest case, you can replace manual allocations of xActor and a subsequent @ into new PxActor(), and any variable^.Gender access to variable.ActorField.Gender.

    Just during the refactoring itself, it would also be possible to use C#'s pointers. They are a bit limited compared to C/Pascal's, but they might work for your cases. Except for that string value. However, pointers have lots of costs, so you don't want to use them unless they are a good idea, and this isn't that case :)

    In other words, it's usually a bad idea to do a 1:1 translation from Pascal to C#. You need to figure out what the semantics behind all the stuff is. Finding all the usages of a given type is going to be a huge chore. Translating line-by-line can easily paint you into a corner. C# is a very safe language, and CLR is very good at making sure everyone can talk with each other, but this also means a few differences in stuff like value/reference passing and similar. Now, IIRC, Pascal has value semantics by default, so using struct and similar should mostly work well in C# as well. You'll have to analyze any use of pointers, though. Sometimes, you can use C#'s out or ref instead of a pointer - go for that. But the case you have here isn't quite like that - it's a pointer stored in another type, not just passed as an argument. However, that still doesn't tell us much about how this is supposed to work in practice - maybe it's just a way to work around Pascal's limitations; maybe you'd use List<xActor> in C# instead of array of PxActor.

    Of course, that's usually the best option. Where possible, use idiomatic C#, instead of just trying to code Pascal in C#. While there are many similarities, there's also a large amount of differences that can bite you, and make your work much harder than necessary. Find the places where List<SomeType> is going to work better than array of PSomeType. Find the places where ref and out can be used instead of PSomeType. Find where struct makes sense, and where class would be better. This applies to many subtle differences that can ruin your day, so you'll probably be finding many issues over time, but it's a journey :)