bruant.d at gmail.com
Sat Feb 2 07:34:20 PST 2013
Action proxies were born as a fork to notification proxies . Both
were attempts to get rid of invariant checks which have some cost. It's
probably too late to bring such a change in the proxy design, but I have
given more thoughts to it, so I'll share it, in the hope it'll fuel
people's thoughts on proxies.
I had issues with potential dangers of action proxies, but they're
isolated to the handler author and only in already complex cases. Since
proxies are a expert feature, the additional complexity in already
complex cases is probably acceptable.
Tom mentioned a per-trap-invocation cost . Some ideas can make this
cost disappear or so small it becomes acceptable.
In my experience, a lot of traps end with the statement:
It would be nice if this was made implicit. Notification proxies allow
for this implicity. It would be nice if action proxies did too.
The action is the equivalent of "Reflect.trap(...trapArgs)". It is
optional to call it. There is one action function per trap (not per
invocation, only per trap type).
When called, the "action" performs "Reflect.trap(...trapArgs)", stores
the value in a slot and returns the value or throws.
Answers to Mark's questions:
1) what happens if the trap does not call action?
=> Exactly the same thing than with notification proxies: an implicit
2) what happens if the trap calls action more than once?
=> The best thing I've come up with is to make the function stateful
(keep in mind that it's a theorical model, I'll talk optimizations
below) and have one slot per trap invocation. Calling action fills the
slot with the return value, the end of trap invocation empties the slot
to use it as termination value (return value or boolean). This slot
semantics is necessary anyway for action proxies (to remember the values
to return in case of nested proxies).
So calling twice just changes the slot value.
Calling the action outside of a related trap invocation timeframe throws
(no slot to fill in)
3) do actions ever return anything, in case the trap wants to pay
attention to it?
=> yes, the return value of Reflect.trap(...trapArgs)
4) are there any return values from the trap that the proxy would pay
=> No. The return value is ignored.
5) if the original operation performed by action throws, should the
action still just return to the trap normally?
=> No, forward the thrown exception.
6) what happens if the trap throws rather that returning?
=> The error thrown is forwarded to the caller, regardless of whether
action has been called.
# Stateful per-trap function and abusive authority
What if malicious code gets all action functions and call them
maliciously? In order to be malicious, the code would have to call the
function in the middle of a trap invocation. The effect of the trap is
Reflect.trap(...trapArgs) (not even change the return value) which was
planned to be done implicitly or explicitly anyway.
The attack case is when action had been called, modification was
performed on the target and action wasn't planned to be called after the
modification (and the attacker does call it within the invocation
timeframe). Arguably, this is so subtle, harmless and easy to protect
against that stateful actions can't be considered as abusive authority.
# Optimization opportunities
Since the calling the action is optional, before-traps won't even call
it, won't even mention it, so the trap-invocation-slot semantics can be
bypassed and the cost of this kind of action proxy is equivalent to
This type of action proxy is sort of the fusion between notification
proxies and original action proxies. By design, they remove the need for
invariant checks. Their cost is one function per trap and the
slot-per-trap-invocation semantics which will be ignored if the action
isn't called explicitly. For the handler author, there is an additional
action argument for each trap which is a bit boilerplate-y, but you only
need it if you call it.
I feel it could work. Too late?
More information about the es-discuss