22

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?

Community
  • 1
  • 1
Mr.Wizard
  • 23,689
  • 5
  • 41
  • 116
  • +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... – Simon Oct 27 '11 at 08:57
  • 1
    @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. – Mr.Wizard Oct 27 '11 at 09:41
  • 3
    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? – Mr.Wizard Oct 27 '11 at 09:50
  • @Mr. You could copy Attributes ... I am not sure why you think `this is neither clean nor fully correct`. Can you explain further? – Dr. belisarius Oct 27 '11 at 14:03
  • 5
    Just documenting history http://i.stack.imgur.com/3ODWy.png – Dr. belisarius Oct 27 '11 at 14:08
  • 1
    @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. – Mr.Wizard Oct 28 '11 at 06:42
  • @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 :D – Dr. belisarius Oct 28 '11 at 06:52
  • @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. – Mr.Wizard Oct 28 '11 at 07:02
  • Leonid took a run at cloning a symbol in [this SO answer](http://stackoverflow.com/questions/6579644/savedefinitions-considered-dangerous/6580284#6580284). – WReach Oct 29 '11 at 04:47
  • @WReach, Mr.Wizard My cloning mechanism can not handle internal `...Values`, and even for the top-level is not without flaws. – Leonid Shifrin Nov 05 '11 at 01:22
  • @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). – Leonid Shifrin Nov 05 '11 at 01:34
  • @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 context`symbol 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 context`symbol syntax. Method overriding in OOP risk the same kind of confusions, but at least the gains _may_ justify the means. – Dr. belisarius Nov 05 '11 at 03:22
  • @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. – Leonid Shifrin Nov 06 '11 at 16:04

2 Answers2

11

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.

Leonid Shifrin
  • 22,129
  • 4
  • 66
  • 98
  • 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` ? – Mr.Wizard Nov 05 '11 at 04:36
  • @Mr.Wizard 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). – Leonid Shifrin Nov 06 '11 at 16:10
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.

celtschk
  • 18,046
  • 2
  • 34
  • 61
  • While I was well aware of this method before I asked the question, this is a valid answer, so +1, and welcome to StackOverflow. – Mr.Wizard Nov 06 '11 at 15:54