[Kde-bindings] Qyoto: new features
Richard Dale
richard.dale at telefonica.net
Tue Apr 10 17:25:12 UTC 2012
On Tuesday, April 10, 2012 01:10:32 AM Dimitar Dobrev wrote:
> As far as I can see QFlags is used only on enums that support bitwise
> operation, i.e. that are defined as 1, 2, 4, 8, etc. So it is impossible to
> produce an invalid enum value using bitwise operations. As I said, QFlags
> exists only because C++ accepts an integer where an enum value is required
> thus violating type safety - a drawback C# does not have with its enums,
> that is, calling MyMethod(MyEnum myEnum) with an integer (or a short, long,
> etc.) fails to compile. So, if C++ enums were type-safe as C# enums, there
> would be no QFlags because it'd serve no purpose. And then the one
> difference between a working and a non-working flags enum would be that the
> first one is correctly (1, 2, 4...) defined. Thank you for your opinion on
> the matter, I appreciate it. I also appreciate your sample implementations
> but I want the generated API to be, besides correct, as simple as possible.
No, I don't think you are correct. C# has exactly the same problem as C++. If
you AND or OR two enums together you don't get an enum type in either C++ or
C#. For instance, from my example:
public class FlagsTest
{public enum MyEnum : uint {
ValA = 0x0,
ValB = 0x1,
ValC = 0x2,
ValD = 0x4
}
public void MyMethod(FlagsTest.MyEnum flags) {
...
}
...
}
If you call MyMethod(MyEnum.ValA & MyEnum.ValB) you will get an error in C#.
If you then define MyMethod() like this:
public void MyMethod(uint flags) {
...
}
You can call MyMethod(MyEnum.ValA & MyEnum.ValB) OK, but you can also call it
with MyMethod(0x16) and it willl work fine. With my QFlags example class, the
first call will work, but 0x16 will give a compile error.
I needed to add this implicit type conversion method to the class so that you
can pass just an enum to a method taking a QFlags<T> argument type:
public static implicit operator QFlags<T>(T f1) {
uint i1 = Convert.ToUInt32(f1);
return new QFlags<T>(i1);
}
Here is a revised version of my example program with three methods; the first
takes an enum, the second a uint and the third takes a QFlags<MyEnum>. I've
added the line number of the method call as a comment along with whether it
gets flagged with a compile error:
using System;
public class QFlags<T> where T : struct
{
public uint i;
public QFlags(T flags) {
i = Convert.ToUInt32(flags);
// Throw an exception if this conversion fails
}
public override string ToString() {
return i.ToString();
}
public QFlags(uint flags) {
i = flags;
// Throw an exception if this conversion fails
}
// User-defined conversion from Digit to double
public static implicit operator QFlags<T>(T f1) {
uint i1 = Convert.ToUInt32(f1);
return new QFlags<T>(i1);
}
public static QFlags<T> operator|(QFlags<T> f1, T f2) {
uint i2 = Convert.ToUInt32(f2);
// Throw an exception if this conversion fails
return new QFlags<T>(f1.i | i2);
}
public static QFlags<T> operator&(QFlags<T> f1, T f2) {
uint i2 = Convert.ToUInt32(f2);
// Throw an exception if this conversion fails
return new QFlags<T>(f1.i & i2);
}
}
public class FlagsTest
{
public enum MyEnum : uint {
ValA = 0x0,
ValB = 0x1,
ValC = 0x2,
ValD = 0x4
}
public void MyMethod1(MyEnum flags) {
Console.WriteLine(flags);
}
public void MyMethod2(uint flags) {
Console.WriteLine(flags);
}
public void MyMethod3(QFlags<MyEnum> flags) {
Console.WriteLine(flags);
}
static public void Main()
{
FlagsTest test = new FlagsTest();
QFlags<MyEnum> f1 = new QFlags<MyEnum>(MyEnum.ValB);
QFlags<MyEnum> f2 = f1 & MyEnum.ValC;
/* 108 ERROR */ test.MyMethod1(f2 | MyEnum.ValD);
/* 109 ERROR */ test.MyMethod2(f2 | MyEnum.ValD);
/* 110 */ test.MyMethod3(f2 | MyEnum.ValD);
/* 112 ERROR */ test.MyMethod1(0x16);
/* 113 */ test.MyMethod2(0x16);
/* 114 ERROR */ test.MyMethod3(0x16);
/* 116 */ test.MyMethod1(MyEnum.ValD);
/* 117 ERROR */ test.MyMethod2(MyEnum.ValD);
/* 118 */ test.MyMethod3(MyEnum.ValD);
}
}
Here are the compile errors for the above code:
crawfish rdale 872% gmcs hello.cs
hello.cs(108,30): error CS1502: The best overloaded method match for
`FlagsTest.MyMethod1(FlagsTest.MyEnum)' has some invalid arguments
hello.cs(91,17): (Location of the symbol related to previous error)
hello.cs(108,30): error CS1503: Argument `#1' cannot convert
`QFlags<FlagsTest.MyEnum>' expression to type `FlagsTest.MyEnum'
hello.cs(109,30): error CS1502: The best overloaded method match for
`FlagsTest.MyMethod2(uint)' has some invalid arguments
hello.cs(95,17): (Location of the symbol related to previous error)
hello.cs(109,30): error CS1503: Argument `#1' cannot convert
`QFlags<FlagsTest.MyEnum>' expression to type `uint'
hello.cs(112,30): error CS1502: The best overloaded method match for
`FlagsTest.MyMethod1(FlagsTest.MyEnum)' has some invalid arguments
hello.cs(91,17): (Location of the symbol related to previous error)
hello.cs(112,30): error CS1503: Argument `#1' cannot convert `int' expression
to type `FlagsTest.MyEnum'
hello.cs(114,30): error CS1502: The best overloaded method match for
`FlagsTest.MyMethod3(QFlags<FlagsTest.MyEnum>)' has some invalid arguments
hello.cs(99,17): (Location of the symbol related to previous error)
hello.cs(114,30): error CS1503: Argument `#1' cannot convert `int' expression
to type `QFlags<FlagsTest.MyEnum>'
hello.cs(117,30): error CS1502: The best overloaded method match for
`FlagsTest.MyMethod2(uint)' has some invalid arguments
hello.cs(95,17): (Location of the symbol related to previous error)
hello.cs(117,30): error CS1503: Argument `#1' cannot convert
`FlagsTest.MyEnum' expression to type `uint'
Compilation failed: 10 error(s), 0 warnings
-- Richard
> ________________________________
> From: Richard Dale <richard.dale at telefonica.net>
> To: KDE bindings for other programming languages <kde-bindings at kde.org>
> Sent: Monday, April 9, 2012 11:35 PM
> Subject: Re: [Kde-bindings] Qyoto: new features
>
>
> On Monday, April 09, 2012 01:27:35 PM Dimitar Dobrev wrote:
>
> It works because while QFlags are not technically enums, they do nothing but
> provide type safety for C++ enums, that is, practically they are enums. On
> the C# side, enums are natively type-safe so it is completely correct to
> replace QFlags with Enum.
>
>
> Well no I don't think that's right. If you pass 'EnumA & EnumB' as a
> argument that value isn't an enum, it is an unsigned int. The QFlags stuff
> is about constructing unsigned ints from enums that are AND'd and OR'd
> together in a type safe manner.
> -- Richard
> _______________________________________________
> Kde-bindings mailing list
> Kde-bindings at kde.org
> https://mail.kde.org/mailman/listinfo/kde-bindings
More information about the Kde-bindings
mailing list