[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