C#: How to declare multiple similar structs? - c#

My app uses several "handles" (all IntPtr's) of varying "type".
I want to help ensure that the correct handle type are passed to my various methods... if I used IntPtr for them all then there's no hint that the method takes handle type A or handle type B.
If L were in C++ land I could use typedefs:
typedef uint32 HdlA;
typedef uint32 HdlB;
and now I have two types, HdlA and HdlB, both of which are generic U32's under the hood.
In C++ I could also use a macro to declare the structs.
Additionally, for marshaling reasons, I need these to be value types... can't use a class (naturally, if I could use class that would solve everything).
All handles have essentially identical definitions:
public struct HdlA
{
private IntPtr _h;
public bool IsValid get { return (_h != IntPtr.Zero);} }
//public HdlA() { _h = IntPtr.Zero; } // C# disallows arg-less ctor on struct
public HdlA(IntPtr h) { _h = h; }
public void Invalidate() { _h = IntPtr.Zero; }
public static implicit operator IntPtr(HdlA hdl) { return hdl._h; }
}
public struct HdlB
{
private IntPtr _h;
public bool IsValid get { return (_h != IntPtr.Zero);} }
//public HdlB() { _h = IntPtr.Zero; } // C# disallows arg-less ctor on struct
public HdlB(IntPtr h) { _h = h; }
public void Invalidate() { _h = IntPtr.Zero; }
public static implicit operator IntPtr(HdlB hdl) { return hdl._h; }
}
... etc ...
I certainly can do this longhand - I can declare 5 or 6 identical blocks of code where only the struct names vary - but that's not very elegant.
I've considered using an Interface, but that disallows member fields, so no luck there.
What I'd love is to have a base struct then have HdlA, HdlB, etc simply derive off the base. But C# disallows base types in structs.
This seems like something that should have an easy and elegant solution, but it's escaping me :(
Any ideas?

One solution is to use only one struct with all common fields and add a field(int or Enum) that shows the type of the struct you want to use. Of course if you were able to use classes you would have used Inheritance but in this scenario adding a HandleType field may solve the problem.
You can then check that field in each method to see the right struct has been passed or not.

You don't provide a great deal of context in your question, so I'm stabbing wildly in the dark here.
It might be possible to use classes in your situation, after all. Declare the abstract base class, derive HndlA and HndlB from it, and provide a ToHandle() method on the base class that converts the class to a struct. The value from ToHandle() would be the object you marshal.
Again, just stabbing wildly in the dark.

In C++ I could also use a macro to declare the structs.
In C# you can use a T4 template.
Or strictly, it's not C# itself, though it can use C# as both the script language, and the output, and it can be part of the build in pretty much any build tool for C# (VisualStudio, MonoDevelop, SharpDevelop, Nant) other than just calling the compiler itself.
Create a file with a .tt or .t4 extension like:
<## template language="C#" #>
<## output extension=".generated.cs" #>
namespace SomeNamespace
{
<#
foreach(string name in new string[]{"HdlA", "HdlB", /*… and so on… */})
{#>
public struct <#=name#>
{
private IntPtr _h;
public bool IsValid
{
get { return (_h != IntPtr.Zero); }
}
public <#=name#>(IntPtr h)
{
_h = h;
}
public void Invalidate()
{
_h = IntPtr.Zero;
}
public static implicit operator IntPtr(<#=name#> hdl)
{
return hdl._h;
}
}
<#}#>
}
It works pretty much as ASP.NET does, but produces a local file. Here we use it to produce a .cs file that will then be part of the compilation, rebuilding the .cs file first if necessary. Alas, while it's a generated file, it causes problems if you don't include it in your source control (must start a question on that irritation).
Here is a real example of mine that's a bit more realistic. Here rather than wanting similar classes with different names, I wanted different methods with different types, but it's the same basic principle.
By the way,
// C# disallows arg-less ctor on struct
Depending on how you look at it, you could also say that it insists that you must have a predefined arg-less zero-filling constructor, that you can't get rid of or replace (there's [usually] no such method, but we do use new blah() in the calling C#). While it's possible in .NET to do otherwise, the differences in the cases where it is called or where zero-filling happens cause enough confusion that insisting that the constructor match zero-filling does save some problems.

Related

How to deal with covariant return types with SWIG for C#?

I am currently using SWIG to generate C# bindings for a third party C++ codebase. I've mostly gotten things working, but there is one thing I'm struggling with. In the codebase, there is a "clone()" method in many of their classes which returns a copy of the calling object. The method uses covariant return types in the C++ code to return an object of the given class's type, but, due to C# not supporting covariant return types, the return types of the clone methods in the generated C# code are all that of the base class.
Is there a method within SWIG to change the return type of all "clone()" methods to match that of the class in which they reside?
I tried using typemap with
%typemap(cstype) *::clone "$csclassname"
and similar variations, but received errors when trying to generate the bindings.
The only "working" method I've found is to use
%ignore *::clone;
then use typemap(cscode) to redefine the clone method with the correct type for all classes that use it, but that is extremely tedious.
I think I just don't completely understand how SWIG typemaps work/if they can work with specific methods like this. If anyone has suggestions for a better way to do this and/or an explanation that could help clarify things for me, it would be greatly appreciated. Thank you.
Edit: Adjusted description to identify the problem as C# not supporting covariant return types.
Edit 2: To clarify, C# 9.0 supports covariant return types, but earlier versions do not. I am using an earlier version for compatibility with a Unity project. I may be able to upgrade the project and my C# version for covariant return type compatibility, though I'm not sure if SWIG's C# tool is compatible with C# 9.0. I wanted to check if there is a workable SWIG solution for my current C# and Unity versions before pursuing that potential option.
Sample Code to Reproduce Issue:
Parent.h
#ifndef PARENT_H
#define PARENT_H
class Parent
{
public:
int val1;
Parent::Parent() = default;
Parent::Parent(const Parent &copiedObject);
virtual Parent* clone() const;
};
#endif
Parent.cpp
#include "Parent.h"
Parent::Parent(const Parent &copiedObject)
{
val1 = copiedObject.val1;
}
Parent* Parent::clone() const
{
Parent* clone = new Parent(*this);
return clone;
}
Child.h
#ifndef CHILD_H
#define CHILD_H
#include "Parent.h"
class Child : public Parent
{
public:
int val2;
Child::Child() = default;
Child::Child(const Child &copiedObject);
Child* clone() const override;
};
#endif
Child.cpp
#include "Child.h"
Child::Child(const Child &copiedObject) : Parent(copiedObject)
{
val1 = copiedObject.val1;
val2 = copiedObject.val2;
}
Child* Child::clone() const
{
Child* clone = new Child(*this);
return clone;
}
CSharpModule.i
%module CSharpModule
%{
#include "Parent.h"
#include "Child.h"
%}
%newobject *::clone;
%include "Parent.h"
%include "Child.h"
clone() method in generated Child.cs
public override Parent clone() {
global::System.IntPtr cPtr = CSharpModulePINVOKE.Child_clone(swigCPtr);
Child ret = (cPtr == global::System.IntPtr.Zero) ? null : new Child(cPtr, true);
return ret;
}
Due to lack of support for covariant return types in C#, the clone() method would need to change to "new" instead of "override (SWIG's %csmethodmodifiers directive) in the derived class:
Desired clone() method
public new Child clone() {
global::System.IntPtr cPtr = CSharpModulePINVOKE.Child_clone(swigCPtr);
Child ret = (cPtr == global::System.IntPtr.Zero) ? null : new Child(cPtr, true);
return ret;
}
I don't know where you get your information, but your entire premise is wrong. C# definitely supports covariant return types:
abstract class B
{
public abstract B Build();
}
class D : B
{
public override D Build() => new();
}
That said, this feature in either language adds essentially nothing, since any "correct" OOP program will use the base class' (or interface's) methods. If you find yourself constantly down-casting to get the more specific version of the function, you should probably rethink your design.
After all, the code generated is identical with or without this feature. This is a compile-time only feature.

Does C# have zero-cost abstractions?

I normally program in languages that have the concept of zero-cost abstractions like C++ and Rust.
Currently I'm working in a project that uses C# language. So I was wondering if I can safely create abstractions and higher level code without compromising the performance.
Is that possible in C# or for performance critical code I should just do as low level code as possible?
Just as an example I encountered in my code (don't focus too much on this example, my question is more high level), I needed a function that would return multiple values, for that, my first approach was to use a tuple, so something like this:
public (int, int, float) Function();
or Abstract this tuple into a struct:
public struct Abstraction { int value1; int value2; float value3; };
public Abstraction Function();
What I expected is that the compiler would optimize the Tuple or the Abstraction struct away and simply use the primitive values directly. But what I found is that writing the code using out parameters would improve performance:
public void Function(out int value1, out int value2, out float value3);
I'm guessing the reason is because in the out function, there is no Tuple or Abstraction struct creation.
The problem with the out function version is that I really hate to use parameters as return values, since it seems more like a hack to a language limitation.
So, in the end I'm not sure if I'm just not using the correct configuration so the JIT could use zero-cost abstraction or this is simply not possible or not guaranteed in C#.
First of all, I don't think it makes sense to say that languages "have zero-cost abstractions". Consider the abstraction of function. Is it zero-cost? Generally speaking, it is zero-cost only if it's inlined. And while C++ compilers tend to be really good about inlining functions, they don't inline all functions, so function in C++ is strictly speaking not a zero-cost abstraction. But this difference only matters rarely in practice, which is why you can usually consider a function to be zero-cost.
Now, modern C++ and Rust are designed and implemented in such a way that they make abstractions zero-cost as often as possible. Is this different in C#? Kind of. C# is not designed with such focus on zero-cost abstractions (e.g. invoking a lambda in C# always involves what's effectively a virtual call; invoking a lambda in C++ does not, which makes it much easier to make it zero-cost). Also, JIT compilers generally can't afford to spend as much time on optimizations like inlining and so they generate worse code for abstractions than C++ compilers. (Though this might change in the future, since .Net Core 2.1 introduced a tiered JIT, which means it has more time for optimizations.)
On the other hand, the JIT compiler is tweaked to work well for real code, not for microbenchmarks (which I assume is how you came to the conclusion that returning a struct has worse performance).
In my microbenchmark, using a struct indeed had worse performance, but it was because JIT decided not to inline that version of Function, it was not because of the cost of creating a struct, or anything like that. If I fixed that by using [MethodImpl(MethodImplOptions.AggressiveInlining)], both versions achieved the same performance.
So, returning a struct can be a zero-cost abstraction in C#. Though it's true that there is smaller chance of that happening in C# than in C++.
If you want to know what is the actual effect of switching between out parameters and returning a struct, I suggest you write a more realistic benchmark, not a microbenchmark, and see what the results are. (Assuming I got it right that you used a microbenchmark.)
Yes, you "can"; but is very difficult to control. So, you always had to test and measure.
A practical example with "zero cost abstraction":
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class App
{
interface IMessages {
string Welcome{ get; }
string Goodbye { get; }
}
partial struct EnglishMessages : IMessages {
public string Welcome {
get { return "Welcome"; }
}
public string Goodbye {
get { return "Goodbye"; }
}
}
partial struct SpanishMessages : IMessages {
public string Welcome {
get { return "Bienvenido"; }
}
public string Goodbye {
get { return "Adios"; }
}
}
static partial class Messages
{
public static SpanishMessages BuildLang {
get { return default; }
}
}
public static void Main() {
Console.WriteLine(Messages.Welcome);
Console.WriteLine(Messages.Goodbye);
}
static partial class Messages
{
public static string Welcome {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return GetWelcomeFrom(BuildLang); }
}
public static string Goodbye {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return GetGoodbyeFrom(BuildLang); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetWelcomeFrom<T>()
where T : struct, IMessages
{
var v = default(T);
return v.Welcome;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetWelcomeFrom<T>(T _)
where T : struct, IMessages
{
return GetWelcomeFrom<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetGoodbyeFrom<T>()
where T : struct, IMessages
{
var v = default(T);
return v.Goodbye;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetGoodbyeFrom<T>(T _)
where T : struct, IMessages
{
return GetGoodbyeFrom<T>();
}
}
#region
[StructLayout(LayoutKind.Explicit, Size = 0)]
partial struct EnglishMessages { [FieldOffset(0)] int _; }
[StructLayout(LayoutKind.Explicit, Size = 0)]
partial struct SpanishMessages { [FieldOffset(0)] int _; }
#endregion
}
You can able to understand the tricks with this code:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class App
{
interface IMessage {
string Value { get; }
bool IsError { get; }
}
static class Messages
{
// AggressiveInlining increase the inline cost threshold,
// decreased by the use of generics.
//
// This allow inlining because has low cost,
// calculated with the used operations.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetValue<T>()
where T : struct, IMessage
{
// Problem:
// return default(T).Value
//
// Creates a temporal variable using the CIL stack operations.
// Which avoid some optimizers (like coreclr) to eliminate them.
// Solution:
// Create a variable which is eliminated by the optimizer
// because is unnecessary memory.
var v = default(T);
return v.Value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsError<T>()
where T : struct, IMessage
{
var v = default(T);
return v.IsError;
}
}
// The use of partial is only to increase the legibility,
// moving the tricks to the end
partial struct WelcomeMessageEnglish : IMessage {
public string Value {
get { return "Welcome"; }
}
public bool IsError {
get { return false; }
}
}
partial struct WelcomeMessageSpanish : IMessage {
public string Value {
get { return "Bienvenido"; }
}
public bool IsError {
get { return false; }
}
}
public static void Main() {
Console.WriteLine(Messages.GetValue<WelcomeMessageEnglish>() );
Console.WriteLine(Messages.GetValue<WelcomeMessageSpanish>() );
}
// An struct has Size = 1 and is initializated to 0
// This avoid that, setting Size = 0
#region
[StructLayout(LayoutKind.Explicit, Size = 0)]
partial struct WelcomeMessageEnglish { [FieldOffset(0)] int _; }
[StructLayout(LayoutKind.Explicit, Size = 0)]
partial struct WelcomeMessageSpanish { [FieldOffset(0)] int _; }
#endregion
}
I "tested" this in CoreClr, Roslyn, Mono and the abstraction has "zero cost":
App.Main()
L0000: push ebp
L0001: mov ebp, esp
L0003: mov ecx, [0xfd175c4]
L0009: call System.Console.WriteLine(System.String)
L000e: mov ecx, [0xfd17628]
L0014: call System.Console.WriteLine(System.String)
L0019: pop ebp
L001a: ret
For coreclr and roslyn, you can view the asm in SharpLab: Here.
And for mono (in GNU/Linux):
mono --aot zerocost.exe
objdump -d -M intel zerocost.exe.so > zerocost.exe.so.dump
cat zerocost.exe.so.dump #Looking for <App_Main>
When you return something, you always create a new object – you save that step completely when just working "in place" with your out parameters.
Then, you have things that your compiler can't simply optimize away – I'd have to tell you a bit about strict aliasing rules in C, but I don't know C# enough to know whether similar things apply here.
So, in general, creating an object of tuple or Abstraction type is not optimizable away. You specifically specified you wanted to return an object of that type, so that object has to be created by a "general" compilation of the function. You could argue that the compiler knows the context in which Function is called and could infer that it's OK to not generate the object but directly work as if these were reference to the things that you assign the fields of Abstraction to later, but here aliasing rules might get really complicated, and that will in general be logically impossible to do.

Self referencing generic member in struct

I need to broaden my understanding of how structs are compiled when using generics.
I have the following code, which works
public struct TestStruct
{
public GenericStruct<SecondTestStruct> Header;
public int TestValue;
}
public struct GenericStruct<T>
{
public int MessageSize => System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
}
public struct SecondTestStruct
{
public int TestValue;
}
static void Main(string[] args)
{
TestStruct test = new TestStruct();
Console.WriteLine($"Size of test is: {test.Header.MessageSize}");
}
This prints 'Size of test is: 4'
However, if I change TestStruct to attempt to provide its own size:
public struct TestStruct
{
public GenericStruct<TestStruct> Header;
public int TestValue;
}
I get a runtime error: System.TypeLoadException: Could not load type 'TestStructGenerics.TestStruct' from assembly.
I'm guessing it has to do with the compiler being unable to create the struct compile time. Or perhaps a problem with circular references when handling the generic resolution.
EDIT:
I just realized that I can achieve what I want by changing the second case to:
public struct TestStruct
{
public GenericStruct<TestStruct> Header => new GenericStruct<TestStruct>();
public int TestValue;
}
According to Eric Lippert's comments in this Roslyn issue, it is unclear whether this problem is a CLR type loader limitation or whether programs of this sort are invalid, and, if they are invalid, whether the C# compiler should detect it and emit an error. Practically, it appears that, until the authorities decide, we have to avoid type loops between structs regardless of the mode that introduces dependence - instance field (that's never going to work because the struct would be infinite size), static field, implemented generic interface, or generic argument. One can break these struct type loops at compile time by changing some struct in the loop to a class, or at run time by going through object or interface and casting.
See also the corresponding CLR issue.

Does C++ have some analog of C# Type thing to store Types of classes in list / array?

In C# i can create such List to store class types:
List<Type> types_list = new List<Type>();
types_list.add(typeof(int));
types_list.add(typeof(Process)); //and etc
can i do the same in C++?
See typeid and type_info.
Note that you can not use the type_info class to create new instances of the type it represents, as C++ have no support for that.
You can store a type list with boost MPL.
Example:
#include <boost mpl stuff>
int main()
{
typedef boost::mpl::vector<char, int> types;
typedef boost::mpl::push_back<types, Process>::type newTypes;
boost::mpl::at_c<newTypes, 2>::type objectOfTypeProcess;
}
You really shouldn't use this library unless you know what you're doing, so my example isn't that specific. You might have to spend some time to get used to mpl anyway.
It is also possible to create instances dynamically. Inspiring but incomplete code:
class TypeProxy {
public:
virtual ~TypeProxy() = default;
char* create_default() const { return this->create_default_impl(); }
template <typename T>
static scoped_ptr<TypeProxy> CreateProxy ();
private:
virtual void* create_default_impl() const = 0;
};
// A creator class.
template <typename T>
class Concrete : public TypeProxy {
void *create_default_impl() const {
return new T ();
}
};
// Method to create creator proxies.
template <typename T>
scoped_ptr<TypeProxy> TypeProxy::CreateProxy () {
return scoped_ptr<TypeProxy> (new Concrete<T>());
}
Note that this is just some untested scratch code to show the operational mode. Whether to use scoped_ptr is debatable.
You can get more fancy with variadic templates (see e.g. the emplace[_(front|back)] functions in C++11), but it will become complicated as virtual function templates are not allowed, but you somehow have to pass over argument lists nevertheless.
(sidenote: boost::shared_ptr use a similar virtual/template mix, which is why you can use non-polymorphic base classes and custom deleters with it)

using extension methods on int

I'm reading about extension methods, and monkeying around with them
to see how they work, and I tried this:
namespace clunk {
public static class oog {
public static int doubleMe(this int x) {
return 2 * x;
}
}
class Program {
static void Main() {
Console.WriteLine(5.doubleMe());
}
}
}
and it worked as expected, successfully extending int with the doubleMe method, printing 10.
Next, being an old C guy, I wondered if I could do this:
namespace clunk {
public static class BoolLikeC {
public static bool operator true(this int i) { return i != 0; }
public static bool operator false(this int i) { return i == 0; }
}
class Program {
static void Main() {
if ( 7 ) {
Console.WriteLine("7 is so true");
}
}
}
}
I would think if the former would work, then the latter ought to work to make it such that
an int used in a boolean context would call the extension method on int, check to see that
7 is not equal to 0, and return true. But instead, the compiler doesn't even like the
later code, and puts the red squiggly lines under the two this's and says "Type expected".
Why shouldn't this work?
Very clever! A nice attempt, but regrettably we did not implement "extension everything", just extension methods.
We considered implementing extension properties, extension operators, extension events, extension constructors, extension interfaces, you name it, but most of them were not compelling enough to make it into C# 4 or the upcoming version of C#. We got as far as designing a syntax for the sort of thing you mention. We got rather farther on extension properties; we almost got extension properties into C# 4 but it ended up not working out. The sad story is here.
http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx
So, long story short, no such feature, but we'll consider it for hypothetical future releases of the language.
You can of course make a "ToBool()" extension method on int if you really do like the retro C convention that non-zero-means-true.
Extension methods are exactly that—methods.
You cannot make extension operators or properties.
Had that been possible, it would result in very hard-to-read code.
If you aren't familiar with the code base, it's almost impossible to figure out what if (7) means.
As others have said, there's no such thing as extension operators in C#.
The closest you can get, running the risk of facilitating lots of nasty bugs down the line, would be with implicit conversion operators on a custom "bridge" type:
// this works
BoolLikeC evil = 7;
if (evil) Console.WriteLine("7 is so true");
// and this works too
if ((BoolLikeC)7) Console.WriteLine("7 is so true");
// but this still won't work, thankfully
if (7) Console.WriteLine("7 is so true");
// and neither will this
if ((bool)7) Console.WriteLine("7 is so true");
// ...
public struct BoolLikeC
{
private readonly int _value;
public int Value { get { return _value; } }
public BoolLikeC(int value)
{
_value = value;
}
public static implicit operator bool(BoolLikeC x)
{
return (x.Value != 0);
}
public static implicit operator BoolLikeC(int x)
{
return new BoolLikeC(x);
}
}
Unfortunately you cannot introduce new operators, or implement support for existing operators, on types, through extension methods.
Basically, what you want to do cannot be done.
The only way to introduce new operators is to put them in one of the involved types. For binary operators you can put them in your own type, provided your type is one of the two, for unary types you need to put the operator inside the type itself.
Since you can't extend an int in any way, you can't do it.
Console.WriteLine(5.doubleMe());
is equivalent to
Console.WriteLine(oog.doubleMe(5));
Given that, you can see why if ( 7 ) doesn't work.
Extension methods are nothing more than syntax.
As a side note since it is syntax you can call extension methods on null variables because it translates to a normal method call, and methods can take null parameters.
Unfortunately you cannot use extension methods to add operators, and implicit type conversion in C# is implemented as an operator.
In the first instance you are writing an extension method - e.g. extending the functionality of the int data type. In the second code set, you are trying to override the bool operators. These are two totally different things.

Categories

Resources