robk would like the following function:
def check(constraint, target):
try:
constraint.checkObject(target, True)
return True
except Violation:
return False
I'm thinking that it would be slick to put this sort of stuff into a decorator, so that you could define your method as:
@schema(a=str, b=ListOf(int), _return=bool)
def do_something(a, b):
print a + " string only"
print "maximum b", max(b)
return True
The @schema decorator should do two things:
- wrap the method with some precondition/postcondition checks that enforce
the schema on both ends
- set a method attribute that foolscap's deserialization mechanism can see,
so that it can enforce the schema on the inbound tokens as they arrive,
before they are deserialized.
This approach moves the constraint closer to the method definition, which has
its advantages: programmers can glance upwards to see the conditions they
know they can rely upon, and thus don't have to add code to enforce those
constraints themselves. This also allows constraints to be attached to some
methods but not to all of them, and would allow constraints on standalone
functions (not just on methods of class instances).
On the other hand, the RemoteInterface? approach has advantages too. It moves
the interface away from the implementation, but by doing so it means that the
interface is a concentrated bundle of documentation, which is easy to publish
and reference. For one program, I implemented the server half of it and
emailed the RemoteInterface? .py file to zooko, and he implemented the client
half of it without seeing any details of the server implementation.
InterfacesAsDocumentation? is a useful thing.