Hi all,
Daniel left me with a nice little puzzle before he went on vacation:
css::uno::Any a = ...; T t = ...; bool b = (a >>= t);
generally follows the design invariant that t is modified if and only if b is true. (In other words, if the value contained in a cannot be extracted as a value of type T, then extracting fails, and t is left unmodified.) I think this design invariant is good, and should be upheld under all circumstances.
Another design decision of operator >>= is that if a contains an interface reference to an object o, and T is an interface reference type, then extracting succeeds if and only if o.queryInterface(T) succeeeds. (In other words, operator >>= is built on queryInterface.) As we shall see below, this design decision is fragile, in that it does not properly take into account that a might contain a null interface reference.
Now, Daniel detected that the current implementation of >>= breaks the above invariant (about the modification of t) under certain circumstances: If a contains an interface reference to an object o, and o.queryInterface(T) returns null, then b will be false, but the interface reference t will nevertheless be set to null. See <http://www.openoffice.org/issues/show_bug.cgi?id=41709> and <http://www.openoffice.org/servlets/ReadMsg?list=interface-announce&msgNo=713> for his fix.
But the fix reveals another problem that has been lurking in code. Given the UNOIDL interfaces
interface X1 {};
interface X2 {};
interface X2a: X2 {};
interface X2b: X2a {};what should the following lines of code do?
css::uno::Any a(css::uno::Reference< X2a >()); // null reference css::uno::Reference< X1 > x1 = ...; bool b1 = (a >>= x1); css::uno::Reference< X2 > x2 = ...; bool b2 = (a >>= x2); css::uno::Reference< X2a > x2a = ...; bool b2a = (a >>= x2a); css::uno::Reference< X2b > x2b = ...; bool b2b = (a >>= x2b);
In the current implementation, if a contains a null interface refererence of type T1, then b = (a >>= t) only succeeds (sets b to true) if t is a reference to the exact type T1. However, since the current implementation has the described bug and modifies t in such a case independently of whether b is true or false, t will always be set to null, regardless of its type. That is, the current implementation does
b1: false x1: null b2: false x2: null b2a: true x2a: null b2b: false x2b: null
With Daniel's fix in place, this would change to
b1: false x1: unmodified b2: false x2: unmodified b2a: true x2a: null b2b: false x2b: unmodified
This looks unnatural and error-prone: First, it is very confusing that b2 is false (and x2 not set to null), even though X2a is a subtype of X2, and >>= generally allows extracting from subtype to supertype. Second, since >>= is built on queryInterface, which is more-or-less independent of the interface hierarchy, it might also be argued that extracting a null reference of type T1 to type T2 should be done independent of the interface hierarchy, and should thus always succeed. (Note that this is how the current implementation behaves, if you ignore the returned b's and only care for the values of the x's---which is often the case in actual source code.)
I think there are four possible ways out of this dilemma:
1 Leave the current implementation untouched, and do not incorporate Daniel's fix. This would be unfortunate, as the current implementation violates an important design invariant of >>=.
2 Incorporate Daniel's fix as is. This would be unfortunate, as the results are unnatural and error-prone, as detailed above.
3 Incorporate Daniel's fix and change the rules so that extracting a null reference of interface type T1 to a reference of interface type T2 succeeds if and only if T1 is derived from T2. That is, the list would become
b1: false x1: unmodified b2: true x2: null b2a: true x2a: null b2b: false x2b: unmodified
4 Incorporate Daniel's fix and change the rules so that extracting a null reference of interface type T1 to a reference of interface type T2 always succeeds, independent of T1 and T2. That is, the list would become
b1: true x1: null b2: true x2: null b2a: true x2a: null b2b: true x2b: null
I favor the fourth solution, and would suggest implementing it for OOo 2.0, even though it has the slight potential of breaking existing code (as some of the b's would change).
Thoughts, anybody? -Stephan
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
