[Kde-bindings] Qyoto: new features
Richard Dale
richard.dale at telefonica.net
Tue Apr 10 18:00:19 UTC 2012
On Tuesday, April 10, 2012 07:32:01 PM Arno Rehn wrote:
> On 10/04/12 19:25, Richard Dale wrote:
> > 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.
>
> [snip]
>
> I think Dimitar is right here. Enums in C# are specifically designed to
> be used in the same manner that QFlags in Qt is, and you should be able
> to pass ORed and ANDed values to a method that is expecting an enum.
> Maybe the enum needs to be have the Flags attribute set for this to work:
>
> http://docs.go-mono.com/?link=T%3aSystem.FlagsAttribute
>
> As you can see, this really is the intended use case. Also, System.Enum
> has methods like HasFlag() which tests for a flag being set.
Ah yes you're right! What a good language C# is..
I didn't know about the [FlagsAttribute()] attribute. Here is a final version
of my test program using that:
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
{
[FlagsAttribute()]
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);
/* 120 */ test.MyMethod1(MyEnum.ValC | DMyEnum.ValD);
/* 121 ERROR */ test.MyMethod2(MyEnum.ValC | DMyEnum.ValD);
/* 122 ERROR */ test.MyMethod3(MyEnum.ValC | DMyEnum.ValD);
}
}
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'
hello.cs(120,48): error CS0103: The name `DMyEnum' does not exist in the
current context
hello.cs(120,24): 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(120,24): error CS1503: Argument `#1' cannot convert `object'
expression to type `FlagsTest.MyEnum'
hello.cs(121,54): error CS0103: The name `DMyEnum' does not exist in the
current context
hello.cs(121,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(121,30): error CS1503: Argument `#1' cannot convert `object'
expression to type `uint'
hello.cs(122,48): error CS0103: The name `DMyEnum' does not exist in the
current context
hello.cs(122,24): 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(122,24): error CS1503: Argument `#1' cannot convert `object'
expression to type `QFlags<FlagsTest.MyEnum>'
Compilation failed: 19 error(s), 0 warnings
It would be possible to fix QFlags<T> so that it doesn't give an error no line
122, but there is no point as the C# flags attribute has the correct behaviour.
Sorrry for the noise, I think I'll go back to Ruby..
-- Richard
More information about the Kde-bindings
mailing list