pforce and pdelay

plet and phoist are the two main tools to use when focusing on optimizations; this is because they significantly reduce both script size and cost of execution.

pforce and pdelay do slightly increase the size of a script but when used properly they can save you quite a bit on execution costs.

As we know, plu-ts is strictly evaluated, meaning that arguments are evaluated before being passed to a function. We can opt out of this behaviour using pdelay which wraps a term of any type in a delayed type so a term of type int becomes delayed( int ) if passed to pdelay. A delayed type can be unwrapped only using pforce; that finally executes the term.

There are two main reasons for why we would want to do this:

  • delaying the execution of some term we might not need at all
  • prevent to raise unwanted errors

One example of the use of pforce and pdelay is the pif function.

In fact, the base if then else function is pstrictIf, however when we use an if then else statement we only need one of the two arguments to be actually evaluated.

So when we call pif, it is just as if we were doing something like:

pforce(
    pstrictIf( delayed( returnType ) )
    .$( myCondtion )
    .$(
        pdelay( caseTrue )
    )
    .$(
        pdelay( caseFalse )
    )
)

so that we only evaluate what we need.

Not only that, but if one of the two branches throws an error but we don't need it, everything goes through smoothly:

pforce(
    pstrictIf( delayed( int ) )
    .$( pBool( true ) )
    .$(
        pdelay( pInt( 42 ) )
    )
    .$(
        pdelay( perror( int ) )
    )
)

Here, everything is ok. If instead we just used the plain pstrictIf

    pstrictIf( int )
    .$( pBool( true ) )
    .$( pInt( 42 ) )
    .$( perror( int ) ) // KABOOM !!!

this would have resulted in an error, because the error is evaluated before being passed as argument.