develooper 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


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About