Front page | perl.perl5.porters |
Postings from May 2007
assertions, warts and all
Thread Next
From:
Ricardo SIGNES
Date:
May 31, 2007 17:38
Subject:
assertions, warts and all
Message ID:
20070601003819.GA22781@knight.manxome.org
I've been thinking about assertions a lot since my first look through them. I
think they're very dangerous, right now, because their current (and default)
interface is confusing. There is so much awesome stuff coming in 5.10 that I'd
hate to see assertions be the big wart that it introduced, especially since
assertions could be a real boon.
The intent of 5.10 assertions seems to be to introduce a way to have some
amount of code optimized away at compile time based on switches given to perl.
That seems like a swell goal, to me.
The basic implementation is something like this (based on my fumbling
exploration, not on a deep understanding):
* You run perl with -Am=x,y,z to activate assertions x, y, and z using module
m; the default module is assertions::activate; -A seems to be identical to
-M, except that you can omit "m" to get the default and you can't specify a
minimum version or unimport.
The default method of activation involves putting a regex or coderef in
@{^ASSERTING}.
* the assertions that activate or deactivate code inside a lexical scope are
declared, by default, with assertions.pm, which evaluates an expression
with relation to @{^ASSERTING} and affects $^H{assertions}
* code that should be deactivated when assertions are not in effect is marked
with the "assertion" attribute
* when subroutines marked "assertion" are called when assertions are not in
effect, the call is optimized away
PROBLEM: selective deactivation within a block is confusing
Because only SOME code gets deactivated inside a block with assertions
declarations, weird things can happen.
{
use assertions 'validation';
die unless everything_is_fine;
}
If everything_is_fine is a subroutine marked with :assertion, and assertions
are not active, it will return 0, and we will die -- even though the code was
never run. Maybe this is the programmer fault, but clearly the language is
not straightforward, here.
PROBLEM: only named subroutines calls are affected
I've mentioned this before, so I won't linger, but a call to a method or
a reference to a named sub will not be properly deactivated.
PROBLEM: the meaning of @{^ASSERTING} is ill-defined
The module used to change the active assertions (by default 'assertions')
and the module used to activate assertions (by default
'assertions::activate') are not explicitly coupled. You can use a different
assertions.pm-like module here and there, and you can use a different module
when calling -A.
They communicate, now, by sharing an idea of how @{^ASSERTING} works, but
it's not documented.
The current working definition is: an assertion label is active if it matches
a regex in @{^ASSERTING} or if a coderef in @{^ASSERTING} returns true when
passed the label.
At minimum, this needs to be documented. I think we're much better off
saying that an assertion is active if the label is ~~ anything in
@{^ASSERTING}. I thought this wasn't possible because of assertions::compat,
but ::compat isn't actually compat, so I don't think it matters.
PROBLEM: assertions::compat
What a mess. It's not really compatible, it's just another implementation of
assertions. Its docs suggest that you should add assertions::compat to your
@ISA wherever you want to use it.
It should be fired into the sun, or at least removed from core and turned
into its own unrelated implementation. I mean, consider what I said, above,
the point of assertions seemed to be, then read this quote from
assertions::compat:
C<assertions::compat> allows to use assertions on perl versions prior
to 5.9.0 (that is the first one to natively support them). Though,
it's not magic, do not expect it to allow for conditionally executed
subroutines.
What? It's just a mess.
SUGGESTIONS:
* update assertion check to use ~~ and document @{^ASSERTING}
I am happy to submit this patch, but ... is there a reason not to?
* supply a means to assert entire blocks away
asserting EXPR { ... }
If the assertion expression is true, the block is executed. If not, it
isn't. This could be done really easily as subroutine (if the block was
given as a sub) but I think this needs core hacking to make it work (a) as
a compile-time optimization and (b) with a bare block.
With this done, I see no reason for "assertion" to be a core attribute. It
will just lead to the confusing partial-expression-evaluation shown above.
* remove assertions::compat from core
This is not needed, but stops suggestion that the porters believe it's
actually compat. Also, why put the only-needed-for-older-perl module in
the core of the new versions?
--
rjbs
Thread Next
-
assertions, warts and all
by Ricardo SIGNES