<
Occasionally it is necessary to temporarily assign a global flag to perform an action. Consider, for illustration, a procedure that returns the inert form of a procedure. We want it to be able to work with procedures that are local to modules. To do that, we need to temporarily assign the kernel flag opaquemodules to false.
GetInert1 := proc(p::uneval)
local opacity,inert;
    opacity := kernelopts('opaquemodules'=false);
    inert := ToInert(eval(p));
    kernelopts('opaquemodules'=opacity);
    inert;
end proc:
Here is a small module to test this on:
Test := module()
local f;
    f := proc(x) x^2 end proc;
end module:
A quick test indicates that it worked:
GetInert1(Test[f]);
_Inert_PROC(_Inert_PARAMSEQ(_Inert_NAME("x")), _Inert_LOCALSEQ(),
    _Inert_OPTIONSEQ(), _Inert_EXPSEQ(),
    _Inert_STATSEQ(_Inert_POWER(_Inert_PARAM(1), _Inert_INTPOS(2))),
    _Inert_DESCRIPTIONSEQ(), _Inert_GLOBALSEQ(), _Inert_LEXICALSEQ(),
    _Inert_EOP(_Inert_EXPSEQ()))
However, suppose an error occurs during the evaluation of ToInert. For example,
GetInert1(Test[g]);
Error, (in GetInert1) module does not export `g`
Because the error causes the procedure to terminate, the opaquemodules flag was never reset.
kernelopts(opaquemodules);
                                false
To avoid that bug, we use the try statement with a finally clause.
GetInert2 := proc(p::uneval)
local opacity,inert;
    try
        opacity := kernelopts('opaquemodules=false');
        inert := ToInert(eval(p));
    finally
        kernelopts('opaquemodules' = opacity);
    end try;
    inert;
end proc:
Testing shows that this does, indeed, reset the flag when an error occurs.
kernelopts(opaquemodules=true): # manual reset from previous 
GetInert2(Test[f]);
_Inert_PROC(_Inert_PARAMSEQ(_Inert_NAME("x")), _Inert_LOCALSEQ(),
    _Inert_OPTIONSEQ(), _Inert_EXPSEQ(),
    _Inert_STATSEQ(_Inert_POWER(_Inert_PARAM(1), _Inert_INTPOS(2))),
    _Inert_DESCRIPTIONSEQ(), _Inert_GLOBALSEQ(), _Inert_LEXICALSEQ(),
    _Inert_EOP(_Inert_EXPSEQ()))

GetInert2(Test[g]);
Error, (in GetInert2) module does not export `g`

kernelopts(opaquemodules);
                                     true
The previous method works fine, however, it can be slightly improved. Rather than assigning the output of ToInert to a local variable (inert) and then returning that variable after the try statement, we can instead, directly return the output of ToInert. This must be done with an explicit return statement, otherwise the output of the kernelopts statement in the finally clause becomes the return value of the procedure.
GetInert3 := proc(p::uneval)
local opacity;
    try
        opacity := kernelopts('opaquemodules=false');
        return ToInert(eval(p));
    finally
        kernelopts('opaquemodules' = opacity);
    end try;
end proc:
Testing shows that it works properly:
GetInert3(Test[f]);
_Inert_PROC(_Inert_PARAMSEQ(_Inert_NAME("x")), _Inert_LOCALSEQ(),
    _Inert_OPTIONSEQ(), _Inert_EXPSEQ(),
    _Inert_STATSEQ(_Inert_POWER(_Inert_PARAM(1), _Inert_INTPOS(2))),
    _Inert_DESCRIPTIONSEQ(), _Inert_GLOBALSEQ(), _Inert_LEXICALSEQ(),
    _Inert_EOP(_Inert_EXPSEQ()))

GetInert3(Test[g]);
Error, (in GetInert3) module does not export `g`

kernelopts(opaquemodules);
                                     true
Now that the code is working to satisfaction, we might consider whether it is useful to split it into reusable parts. Converting to an inert form is a rather specialized operation, something probably not done frequently. Extracting a local procedure from a module is more generally useful. So we'll make it a separate function, and then call it from GetInert. Here is the procedure for extracting, if necessary, a procedure. A check has been added to verify that p does indeed evaluate to a procedure.
GetProc := proc(p::uneval)
local opacity;
    try
        opacity := kernelopts('opaquemodules=false');
        if not p::procedure then
            error "%1 is not a procedure", p
        else
            return eval(p)
        end if;
    finally
        kernelopts('opaquemodules' = opacity);
    end try;
end proc:
Here is the version of GetInert that uses GetProc.
GetInert4 := proc(p::uneval)
    ToInert(GetProc(p))
end proc:
Now for the tests
GetInert4(Test[f]);
_Inert_PROC(_Inert_PARAMSEQ(_Inert_NAME("x")), _Inert_LOCALSEQ(), _Inert_OPTIONSEQ(), _Inert_EXPSEQ(),
    _Inert_STATSEQ(_Inert_POWER(_Inert_PARAM(1), _Inert_INTPOS(2))), _Inert_DESCRIPTIONSEQ(),
    _Inert_GLOBALSEQ(), _Inert_LEXICALSEQ(), _Inert_EOP(_Inert_EXPSEQ()))

GetInert4(Test[g]);
Error, (in GetProc) module does not export `g`

GetInert4(g);
Error, (in GetProc) g is not a procedure

Please Wait...