Macaulay2 / M2

The primary source code repository for Macaulay2, a system for computing in commutative algebra, algebraic geometry and related fields.
https://macaulay2.com
345 stars 230 forks source link

New notation for shadowed symbols #1184

Open mahrud opened 4 years ago

mahrud commented 4 years ago

Suggestion: replace Package$Symbol with Package::Symbol, which also matches the notation of document tags and is more widely recognized as a namespace operator in C++, Ruby, etc.

DanGrayson commented 4 years ago

I like that notation, and we're already using it in the context of documentation strings, as here:

     Outputs => {
      {TO "BoijSoederberg::CohomologyTally", " dimensions of cohomology groups"}  
      },

In that context it is slightly more general, allowing any documentation node name to the right of the "::", not just symbols.

It would be a little hard to engineer this. The Macaulay2 language knows nothing about packages -- that is a high level concept coded within the language. The way the "$" works is that it is simply one of the characters allowed to be part of an identifier (except at the start).

i6 : a$a$ = 3

o6 = 3

When a package is loaded, the exported symbols are given two names in the dictionary:

i4 : keys ConwayPolynomials.Dictionary

o4 = {conwayPolynomial, ConwayPolynomials$conwayPolynomial}

If we were to add an operator "::" to the language the same way we have added the other operators, such as "+" and "*", it wouldn't work as desired, because in an expression like "x::y", the "y" part would get evaluated. Instead, it would have to work the way "x.y" currently works, with "y" taken as a string of identifier characters, and with the whole thing evaluated after. If we could devise some way for it to work without including the notion of "package" in the language, it would be good. One would also have to arrange for assignment statements like "x::y=z" to work.

Another way to try to do it would be to change the lexical analyzer so identifier names can contain "::" (but not ":"). This would require being able to peek two characters ahead in the stream of input bytes.

mahrud commented 4 years ago

I think it would actually be really useful to have a more general notion of namespaces in M2, so you could define a namespaces even within a package. This would be really useful for large packages like Dmodules or NormalToricVarieties, and also for organizing the Core.

DanGrayson commented 4 years ago

I think it would actually be really useful to have a more general notion of namespaces in M2, so you could define a namespaces even within a package. This would be really useful for large packages like Dmodules or NormalToricVarieties, and also for organizing the Core.

I think we have that: a dictionary is a namespace.

mahrud commented 4 years ago

I'm talking about namespace in the sense of C++: https://en.cppreference.com/w/cpp/language/namespace At least two things would need to be added:

DanGrayson commented 4 years ago

I'm talking about namespace in the sense of C++: https://en.cppreference.com/w/cpp/language/namespace

I, also..

At least two things would need to be added:

  • make a sub-namespace in a package, in a way that the symbols are not automatically in the parent namespace

That's the private dictionary, with the symbols that are not exported.

  • access symbols in a namespace, ideally using (symbol::, Dictionary, Symbol).

It's strings, not symbols, and the syntax is dict#name. Well, you may have to take the value of that symbol, so there's a difference from the way it works with namespaces.

mahrud commented 3 years ago

Once this is working, we should allow something like:

f := PkgA :: myFunction;

for importing something from a different package, but giving it a new name.

I wrote a basic implementation of importFrom, but would like to keep #1236 open to implement a more advanced version that would work with namespaces as in #1184.

Originally posted by @mahrud in https://github.com/Macaulay2/M2/issues/1236#issuecomment-719909345

Using importFrom, the code above would essentially call:

f := first importFrom_PkgA {"myFunction"}