Exposing Symbols to $ContextPath
Asked Answered
A

2

24

There are a variety of Internal`context functions that are useful, such as InheritedBlock, Bag and StuffBag, etc., as well as many useful Developer` functions.

I wish to expose a selection of these symbols such that they may be addressed plainly without the context name, but I do not want to expose all of them by adding Internal` and Developer` to $ContextPath.

I could use a proxy symbol such as Bag = Internal`Bag but this is neither clean nor fully correct, since it is a reference, and e.g. attributes are not inherited.

Is there a way to selectively expose the symbols I want, without resorting to the kluge above?

Accentuate answered 27/10, 2011 at 7:45 Comment(13)
+1 There are lots of useful hidden functions in Internal` and Developer` . You could write a wrapper function to implement your kludge with attributes etc...Remunerative
@Simon, yes, I could, but even that is usually not necessary because heads evaluate first. This is not really a problem per se, but somehow it doesn't seem correct.Accentuate
Rather surprisingly, without using Unprotect or similar tools, one can redefine the context of a System` or Internal` symbol using Context[symbol] = "context`". However, this removes the symbol from its original context, which is unacceptable. Is there any way to assign two different contexts to a symbol?Accentuate
@Mr. You could copy Attributes ... I am not sure why you think this is neither clean nor fully correct. Can you explain further?Holguin
Just documenting history i.sstatic.net/3ODWy.pngHolguin
@belisarius re: your question, it's quite possibly the best or only way to handle this. However, I know it is a pointer, rather than the symbol itself, and for some reason this bothers me.Accentuate
@Mr. But your question seems too convoluted. I mean: you don't want to expose all those symbols, you don't want to prefix with their context, and you don't want to use pointers. I can understand you got to 10K and that feels dizzy, but you want too much today :DHolguin
@belisarius lol -- well, I did not think this was possible, or I wouldn't have asked the question. However, people here have shown how to do what I also thought was impossible, so it is worth asking. From my limited perspective, my question may be condensed to: "Is it possible for a symbol to be cloned to a second context?" but that doesn't explain what I am trying to do, nor does it allow for a solution I have not yet conceived.Accentuate
Leonid took a run at cloning a symbol in this SO answer.Sigismundo
@WReach, Mr.Wizard My cloning mechanism can not handle internal ...Values, and even for the top-level is not without flaws.Zeller
@belisarius I have the same feeling as Mr.Wizard regarding this. The thing he asks for is a new language feature, and does not seem to be fully derivable from the tools we have currently access to. I think, by "not right", Mr.Wizard meant that this should have a solution entirely on the level of namespaces (contexts, parsing), while creating proxies with Set adds the evaluation process to the mix. And I am with him - this indeed does not feel right (to me anyway).Zeller
@Leonid I was joking with Mr. Wizard. Now more serious: there are at lest two valid ways to invoke a symbol in a certain context, both discarded in the question (executing contextsymbol and adding the context to the context path). On the other hand, I think allowing native support for symbol cloning may open loopholes and difficulties in code comprehension that I feel are not justified by the scarce gain of saving the contextsymbol syntax. Method overriding in OOP risk the same kind of confusions, but at least the gains may justify the means.Holguin
@belisarius I am not talking about the cloning of symbols, which is one possible approach to answer the question but perhaps not the best. I rather meant direct import of a given specific symbol, without importing the full context of that symbol - such functionality exists in some languages, e.g. Python. Executing context`symbol is IMO really a poor solution, since it is fragile with respect to changes such as symbols moving to another context, or context renaming, and can lead to regression bugs - it is a kind of hard-coding, destroying somewhat the purpose of modules / packages.Zeller
Z
12

This is IMO a very deep and valid question, and judging by the vote count, I am not alone in thinking this. If we had this feature fully supported on the language level, this would give one a whole new way to manipulate the scoping and encapsulation, and would IMO often allow for a cleaner code and better information hiding. This would be similar to from module-name import name1,name2,... in Python.

Perhaps as many of us, I have tried multiple approaches, but all of them seem fragile and incomplete. The worst case is for packages, for which I have no good solution. For the interactive work in the FrontEnd, here is one which might be acceptable. First define a general macro to make the literal substitutions:

ClearAll[withImported];
SetAttributes[withImported, HoldAll];
withImported[importingRules : {(_Symbol ->  _String) ..}, code_] :=
  With @@ Join[
     Hold[importingRules] /.
      (name_Symbol -> context_String) :>
          With[{eval =
               Block[{$ContextPath = Append[$ContextPath, context]},
                 ToExpression[context <> ToString[Unevaluated@name]]
               ]},
             Set[name, eval] /; True],
     Hold[code]];

withImported[importingRules : {({__Symbol} -> _String) ..}, code_] :=  
    Reverse[Hold @@ Flatten[Unevaluated[importingRules] /.
        ({syms__Symbol} -> s_String) :> Thread[s :> {syms}]], {2}] /. 
        RuleDelayed -> Rule /.
        Hold[expandedRules : ((_Symbol ->  _String) ..)] :> 
             withImported[{expandedRules}, code];

Then, create a function which would incorporate your favorite shortcuts, for example:

shortcutF = 
   Function[code,
     withImported[
       {
         {PackedArrayQ, ToPackedArray, FromPackedArray} -> "Developer`",
         {InheritedBlock, WithLocalSettings} -> "Internal`"
       },
       code
     ],
     HoldAll];

You can now wrap your code in shortcutF and start using the short names. Up to now, this would also work for packages, but you will have to wrap all your code (or at least those pieces which contain short-cuts) in shortcutF, which is not very convenient. As a further convenience step, you may assign the above function to $Pre:

$Pre = shortcutF;

Here are some examples of use:

In[31]:= 
WithLocalSettings[Null,Abort[],Print["Cleanup"]]

During evaluation of In[31]:= Cleanup
Out[31]= $Aborted[]

In[32]:= PackedArrayQ[Range[10]]
Out[32]= True

In[33]:= PackedArrayQ@FromPackedArray[Range[10]]
Out[33]= False

Since With is used under the cover, what really happens is that your short-cut symbols get substituted by fully-qualified symbol names, before the code is executed.

This is as far as I could get, but this feature seems to be particularly crying for a native support from the language.

Zeller answered 5/11, 2011 at 1:6 Comment(2)
Thanks Leonid. Please remind me: have you found a kernel hook that acts before parsing, like CellEvaluationFunction for the FrontEnd? Is it practical to encapsulate the body of a package in a string, such that it starts with parsefunction = ..., body = " ... ", ToExpression@parsefunction@body ?Accentuate
@Accentuate I am not aware of this kind of hook, alas. As to the practicality of using strings in this context, this probably depends on the circumstances, but does not strike me as a generally good solution. I think that we really need either language support for the particular feature you requested, or a programmable reader/parser (which would be even better).Zeller
B
5

A variation of Leonid's answer which applies on an earlier stage:

InternalSymbols={"Bag","BagLength","BagPart","StuffBag"}
$PreRead=#/.(InternalSymbols/.{s_String:>s->"Internal`"<>s})&

After typing this in a notebook, typing

?Bag

gives me

Internal`Bag
Attributes[Internal`Bag]={Protected}

while

?AbsSquare

gives

Information::notfound: Symbol AbsSquare not found.

but

?Internal`AbsSquare

gives

Internal`AbsSquare
Attributes[Internal`AbsSquare]={Listable,NumericFunction,Protected}

However it seems to only work in the notebook interface, not when using math on the command line.

Brogdon answered 6/11, 2011 at 15:21 Comment(1)
While I was well aware of this method before I asked the question, this is a valid answer, so +1, and welcome to StackOverflow.Accentuate

© 2022 - 2024 — McMap. All rights reserved.