Possible to block OwnValues when DownValues already exist?

前端 未结 2 439
野趣味
野趣味 2021-02-01 09:56

For cases where one has already assigned DownValues associated with the name \'a\', is there an accepted way to block the assignment of OwnValues to the same name? (I originally

2条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-01 10:36

    I don't know if this is an "accepted" way, but you could define a rule that prevents Set and SetDelayed from acting upon a:

    Remove[a];
    a[1] := somethingDelayed
    a[2] = somethingImmediate;
    
    a /: HoldPattern[(Set|SetDelayed)[a, _]] := (Message[a::readOnly]; Abort[])
    
    a::readOnly = "The symbol 'a' cannot be assigned a value.";
    

    With this rule in place, any attempt to assign an OwnValue to a will fail:

    In[17]:= a = somethingThatScrewsUpHeads;
    
    During evaluation of In[17]:= a::readOnly:
      The symbol 'a' cannot be assigned a value.
    
    Out[17]= $Aborted
    
    In[18]:= a := somethingThatScrewsUpHeads;
    
    During evaluation of In[18]:= a::readOnly:
      The symbol 'a' cannot be assigned a value.
    
    Out[18]= $Aborted
    

    However, this rule will still allow new DownValues for a:

    In[19]:= a[3] = now;
             a[4] := later
    
    In[20]:= a[3]
    
    Out[20]= now
    
    In[21]:= a[4]
    
    Out[21]= later
    

    Performance

    The rule does not seem to have an appreciable impact on the performance of Set and SetDelayed, presumably since the rule is installed as an up-value on a. I tried to verify this by executing...

    Timing@Do[x = i, {i, 100000000}]
    

    ... both before and after the installation of the rule. There was no observable change in the timing. I then tried installing Set-related up-values on 10,000 generated symbols, thus:

    Do[
      With[{s=Unique["s"]}
      , s /: HoldPattern[(Set|SetDelayed)[s, _]] :=
          (Message[s::readOnly]; Abort[])
      ]
    , {10000}]
    

    Again, the timing did not change even with so many up-value rules in place. These results suggest that this technique is acceptable from a performance standpoint, although I would strongly advise performing performance tests within the context of your specific application.

提交回复
热议问题