develooper Front page | perl.perl6.language | Postings from January 2001

RE: About RFC 271: pre/post handlers (it's more than DBC)

Garrett Goebel
January 25, 2001 11:31
RE: About RFC 271: pre/post handlers (it's more than DBC)
Message ID:
From: Branden []
> For example: suppose sub next_temp calculates a new 
> temperature from an old temperature
> Suppose it only handles Celsius, and we want to be able to 
> handle Fahrenheit and Kelvin also. We could do it by:

if you have a procedure:

sub next_temp ($$) { $_[0]->change_using($_[1]) }

And you wanted to allow it to handle other temperature scales... I wouldn't
change the object attribute's internal temperature scale representation. I
would translate to and from it as necessary. 

pre next_temp { $_[1] = $self->convert($_[1]) if $_[1] =~ /([FKC])$/ }
sub convert { ... }

> Well, that's OK, right? Now suppose you're inheriting it from 
> a class that has a pre-handler for next-temp that states:
> pre next_temp {
>     if ($_[1] < -5) {
>         die "Too cold!!!";
>     } elsif ($_[1] > 50) {
>         die "Too hot!!!";
>     }
> }

This wouldn't be a problem with the code I've suggested. 

RFC 271 section on Inheritance of prefix handlers states:
> This implies that any heritable prefix handlers inherited from
> a base class are executed disjunctively with those heritable
> handlers specified in the derived class. In practice this means
> that the set of heritable prefix handlers from the base class(es)
> is invoked within an eval and if none of them throws an exception,
> that success suffices to satisfy the precondition constraint on
> the method, in which case the heritable prefix handlers of the
> derived class are not called (although the non-heritable handlers
> are still invoked). If the eval terminates because some inherited
> handler threw an exception, then the full set of prefix handlers
> (heritable and non-heritable) for the derived-class are tried
> instead. 

So... even with your code example, the exception thrown by the base pre,
wouldn't matter if the derived pre is satisfied.

This is slightly different from the implementation of Class::Contract where
first the derived class' preconditions are checked, then failing that the

> Another one: suppose I want to return the value in the same 
> format that it
> was given to me. Damian told me that I could do it by:
> Well, that's OK, although I think the conversion back would be a
> post-handler thing.
> But that's a problem in the inheritance case, just as
> before, as also if there are other pre-handlers that would
> be called after this one, they wouldn't be called because
> this one would set $_[-1] and so return this value instead
> of calling the real sub!!!

And you probably should use a post-handler. Damian's example was how to do
it all with a single pre handler, if you wanted. I.e., just like your
original example. TIMTOWTDI. Perhaps there will be a time or implementation
change required when you _do_ want to avoid calling the real sub and
subsequent post handlers?

> The $_[-1] thing is also a bad thing in that it hides the context the
> function was called. What if the function was called in a 
> list context?

RFC 271 section on Prefix Handler Semantics states:
> this (correctly) implies that a handler receives the same
> information from caller and want (RFC 21) as its primary would

How this is implemented... I have no idea. Personally, I find the use of
$_[-1] confusing. In a pre when I first fetch $_[-1], is it the last
argument or the placeholder for the return value?  Or does the placeholder
for the return value only come into existence when you attempt to store to
it? That seems counter to splice(@_, -1, 'foo'). I'd much prefer a keyword
like 'value' which could be used within the context of pre and post

> What I propose is, instead of having pre- and post- handlers, 
> we have pre- and post- conditions that allow or don't allow
> a method to be called. That's what's needed for DBC.

That is what Class::Contract does. I think the pre/post handlers are a
slightly more empowering and potentially obfuscating feature. Handlers can
do more than conditionally check a procedure. They can affect what the real
invocation sees, or usurp the procedure's invocation altogether. 

> What I mean is, DBC's pre- and post- conditions are VERY 
> important, and should be implemented, only shouldn't be
> implemented in a way that leads to wrong stuff, like
> assuming that this same pre/post handler stuff could be
> used to flock files or change parameter values, or any of 
> such stuff. Its inheritance behavior completely makes it
> unstable.

I do kind of agree. DBC is very bondage and discipline... Loosening up the
semantics of pre/post to allow them to "handle" the arguments a that
procedure receives or the actual "implementation" invoked seems more
"perlish", but at odds with the DBC philosophy. Hmm... I wonder if a strict
'handlers' pragma could be arranged? Limiting the generic handler mechanism
into strictly DBC for a specific scope...

However, there is a need for handlers. Note Jarkko's RFC 194:
> This would open up a way towards very nifty features like the
> ubiquitously-requested URL-aware open(). Just install your
> URL-ware prehandler to \CORE::open and off you go. Want
> versioned files? warn() that also transparently does syslog()?
> close() that automatically renames the file to
> file.YYYYMMDD-hhmmss after it has been closed? 

I also imagine, it would allow different versions of modules to interact
others in a sane manner.

I believe Damian's RFC 194 is really just a very nice shoehorn to do both
pre/post handlers and DBC conditionals.

Garrett Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About