[Development] [Feature] Q_INFO: Annotations for classes, methods, properties and enums

Stefan Merettig stefan-merettig at nuriaproject.org
Wed Sep 4 22:32:34 CEST 2013


> I think adding general information to method or properties are a good 
> idea.
> The current tag system is indeed very limited.
> But before trying to get something to general, we need to focus on use
> cases.
Alright, I present to you: libAuth, a authentication framework which 
lets the
dev write simple or complex permission rules right in the code. As 
modern
business logic demands that code is flexible, there's not a big issue 
with
hard-coding certain key values.

   // We need to allows access to employees and the daemons.
   Q_INFO("libAuth.allowedGroups" ARGS "admin", "moderators", "staff", 
"daemons")
   Q_INFO("libAuth.db.connection" ARGS "BillingPermissions")
   class BillingService : public QObject {

     // Customer support may not use this!
     Q_INFO("libAuth.disallowedGroups" ARGS "support")
     public void depositFunds (int credits);

     // Maintenance windows must be respected. Only admins.
     Q_INFO("libAuth.allowedTimeRange" ARGS "20:00", "6:00")
     Q_INFO("libAuth.allowedGroups" ARGS "admin")
     public void startMaintenance ();

   };

Another use-case would be to do contract-based programming or what the 
right
buzzword for that was. (For people who don't know what that is: You 
define
allowed values somewhere where a compiler can error if you don't comply 
to
these.) We may not be able to get the compiler to throw, but we could 
nicely
combine this into a API which gets exposed to a scripting environment:

   Q_INFO("Contract.times" ARGS "0", "99")
   Q_INFO("Contact.itemId.checkSlot" ARGS "checkIfItemIdIsValid")
   bool addItemToCart (int itemId, int times);

This is already a pretty complex use-case. In this example, I say that 
the
arguments, which are matched by their name, must follow certain 
"rules".
That is, the "times" argument must be between 0 and 99. As the check if 
itemId
is pretty complex, we tell the system to instead invoke a slot which 
tests it
for us.

While this approach is not for all users, it's a interesting approach 
in
bigger projects to separate argument validation and the "real" logic. 
This
is especially cool if you have a ton of methods, which all use the same
validation functionality. Instead of doing it x times, you do it once 
actually
and then tell the environment about it directly.

Now try this with a simple key-value store. If we'd not allow multiple 
values,
then this would simply not possible without really ugly hacks. Period.
If we would allow multiple values, but only a argument per item .. 
well, that'd
create a mess for no good. It at least wouldn't improve readability.

> I rather opt for a key/value system.  then it can easily be queried 
> with
> something like.
> QByteArray QMetaMethod::methodInfo(const char *key);
> [...]
> What is really your use case with several argument that cannot be done 
> with
> a key/value system?  Worst case you can do something like
>  Q_INFO(key.arg1 = foo)
>  Q_INFO(key.arg2 = bar)
So, if a user wants to accept a variable amount of arguments, you want 
him to
use "argX", while the internal code counts upwards, and the user of 
this feature
has to keep track of the number scheme too? That's two levels of 
unneded
complexity with a big mess-up potentional. With the proposed API the 
user can't
simply write
   Q_INFO("foo" = "bar")
   Q_INFO("foo" = "baz")
as that would interfere with the concept of a plain key-value store.

Of course you can abuse them to do something "better", but meta 
programming is
already strange enough without weird string hacks all over the place. A 
clean
solution which is easily extend-able in the future may encourage others 
to use
it instead of using those hacks, or not using the current system at all 
because
these hacks are so ugly and weird.

What I would be fine with is allowing a alternative syntax (So allowing 
both):
   Q_INFO("<Name>" [ARGS <Value>, ...])
   Q_INFO("<Name>", "<Value>")

The QMetaInfo class *could* even have a convenience method like
firstArgument(). I'm totally fine with all of these fixes, but the
currently available facts don't show me why my approach is or may be 
harmful.

>> Q_INFO can be prefixed to ...
>> 1) Classes
> 
> We already have Q_CLASS_INFO for classes.
Which I don't like, and IMO this isn't just a reinvention of the wheel, 
as
Q_INFO can do more. Plus, we get a generic method which applies to 
everything.

> BTW,  All of that can be done currently by abusing Q_CLASSINFO
I also could write a const char* as static class member. That's not too 
far
from abusing Q_CLASSINFO for something like this.

> Yes.
> Notice that we could also re-use the "tag" field of the data array for 
> some
> purpose (it would mean the old tag or the info count depending on one 
> of the
> bit or of the revision)
Breaks compatibility. If no one cares, well we could of course re-use 
that
field as "pointer" to a data table in the meta-data structure. But 
that's
really ugly. And the last thing I want is storing something like
"Foo=Bar Baz=House" as string-data. That'd be a nightmare to parse. We 
did
that in Qt4 for the method signature, we now store every part 
individually.
We should not do the same mistake again. The only solution would be 
storing
JSON instead - If that's a solution I don't know.

Sorry for the long mail, but I hope my reasons are a tad clearer now :)




More information about the Development mailing list