@@ -333,56 +333,73 @@ def replace_slots(self, slots, evaluation) -> "Atom":
333333
334334class Symbol (Atom , NumericOperators , EvalMixin ):
335335 """
336- Note: Symbol is right now used in a couple of ways which in the
337- future may be separated.
336+ A Symbol is a kind of Atom that acts as a symbolic variable.
338337
339- A Symbol is a kind of Atom that acts as a symbolic variable or
340- symbolic constant.
338+ All Symbols have a name that can be converted to string.
341339
342- All Symbols have a name that can be converted to string form.
343-
344- Inside a session, a Symbol can be associated with a ``Definition``
340+ A Variable Symbol is a ``Symbol``` that is associated with a ``Definition``
345341 that determines its evaluation value.
346342
347- We also have Symbols which are immutable or constant; here the
348- definitions are fixed. The predefined Symbols `` True``, `` False``,
349- and ``Null`` are like this.
343+ We also have Symbols which in contrast to Variables Symbols have
344+ a constant value that cannot change. System` True and System` False
345+ are like this.
350346
351- Also there are situations where the Symbol acts like Python's
352- intern() built-in function or Lisp's Symbol without its modifyable
353- property list. Here, the only attribute we care about is the name
354- which is unique across all mentions and uses, and therefore
355- needs it only to be stored as a single object in the system.
347+ These however are in class PredefinedSymbol. See that class for
348+ more information.
356349
357- Note that the mathics.core.parser.Symbol works exactly this way.
350+ Symbol acts like Python's intern() built-in function or Lisp's
351+ Symbol without its modifyable property list. Here, the only
352+ attribute we care about is the value which is unique across all
353+ mentions and uses, and therefore needs it only to be stored as a
354+ single object in the system.
358355
359- This aspect may or may not be true for the Symbolic Variable use case too .
356+ Note that the mathics.core.parser.Symbol works exactly this way .
360357 """
361358
362359 name : str
363360 hash : str
364361 sympy_dummy : Any
365- defined_symbols = {}
362+
363+ # Dictionary of Symbols defined so far.
364+ # We use this for object uniqueness.
365+ # The key is the Symbol object's string name, and the
366+ # diectionary's value is the Mathics object for the Symbol.
367+ _symbols = {}
368+
366369 class_head_name = "System`Symbol"
367370
368371 # __new__ instead of __init__ is used here because we want
369372 # to return the same object for a given "name" value.
370- def __new__ (cls , name : str , sympy_dummy = None , value = None ):
373+ def __new__ (cls , name : str , sympy_dummy = None ):
371374 """
372- Allocate an object ensuring that for a given `name` we get back the same object.
375+ Allocate an object ensuring that for a given ``name`` and ``cls`` we get back the same object,
376+ id(object) is the same and its object.__hash__() is the same.
377+
378+ PredefinedSymbol's like System`True and System`False set
379+ ``value`` to something other than ``None``.
380+
373381 """
374382 name = ensure_context (name )
375- self = cls .defined_symbols .get (name , None )
383+
384+ # A lot of the below code is similar to
385+ # the corresponding for numeric constants like Integer, Real.
386+ self = cls ._symbols .get (name )
387+
376388 if self is None :
377- self = super (Symbol , cls ).__new__ (cls )
389+ self = super ().__new__ (cls )
378390 self .name = name
379391
392+ # Cache object so we don't allocate again.
393+ cls ._symbols [name ] = self
394+
380395 # Set a value for self.__hash__() once so that every time
381- # it is used this is fast.
382- # This tuple with "Symbol" is used to give a different hash
383- # than the hash that would be returned if just string name were
384- # used.
385- self .hash = hash (("Symbol" , name ))
396+ # it is used this is fast. Note that in contrast to the
397+ # cached object key, the hash key needs to be unique across *all*
398+ # Python objects, so we include the class in the
399+ # event that different objects have the same Python value.
400+ # For example, this can happen with String constants.
401+
402+ self .hash = hash ((cls , name ))
386403
387404 # TODO: revise how we convert sympy.Dummy
388405 # symbols.
@@ -395,25 +412,8 @@ def __new__(cls, name: str, sympy_dummy=None, value=None):
395412 # value attribute.
396413 self .sympy_dummy = sympy_dummy
397414
398- # This is something that still I do not undestand:
399- # here we are adding another attribute to this class,
400- # which is not clear where is it going to be used, but
401- # which can be different to None just three specific instances:
402- # * ``System`True`` -> True
403- # * ``System`False`` -> False
404- # * ``System`Null`` -> None
405- #
406- # My guess is that this property should be set for
407- # ``PredefinedSymbol`` but not for general symbols.
408- #
409- # Like it is now, it looks so misterious as
410- # self.sympy_dummy, for which I have to dig into the
411- # code to see even what type of value should be expected
412- # for it.
413- self ._value = value
414415 self ._short_name = strip_context (name )
415416
416- cls .defined_symbols [name ] = self
417417 return self
418418
419419 def __eq__ (self , other ) -> bool :
@@ -634,24 +634,47 @@ def to_sympy(self, **kwargs):
634634 return sympy .Symbol (sympy_symbol_prefix + self .name )
635635 return builtin .to_sympy (self , ** kwargs )
636636
637- @property
638- def value (self ) -> Any :
639- return self ._value
640-
641637
642638class PredefinedSymbol (Symbol ):
643639 """
644- A Predefined Symbol of the Mathics system.
640+ A Predefined Symbol is a Constant Symbol of the Mathics system whose value can't
641+ be changed.
645642
646- A Symbol which is defined because it is used somewhere in the
647- Mathics system as a built-in name, Attribute, Property, Option,
648- or a Symbolic Constant.
643+ Therefore, like say, an Integer constant, we don't need to go
644+ through Definitions to get its value.
649645
650- In contrast to Symbol where the name might not have been added to
651- a list of known Symbol names or where the name might get deleted,
652- this never occurs here .
646+ As we do in numeric constants, a PredefinedSymbols Python-equivalent value not its string name
647+ but to its Python-equivalent value. For example for the predefined System`True we
648+ we can set its value to the Python ``True`` value .
653649 """
654650
651+ # Dictionary of PredefinedSymbols defined so far.
652+ # We use this for object uniqueness.
653+ # The key is the PredefinedSymbol object's name, and the
654+ # diectionary's value is the Mathics object representing that Python value.
655+ _predefined_symbols = {}
656+
657+ # We use __new__ here to unsure that two Integer's that have the same value
658+ # return the same object.
659+ def __new__ (cls , name , value ):
660+
661+ name = ensure_context (name )
662+ self = cls ._predefined_symbols .get (name )
663+ if self is None :
664+ self = super ().__new__ (cls , name )
665+ self ._value = value
666+
667+ # Cache object so we don't allocate again.
668+ self ._predefined_symbols [name ] = self
669+
670+ # Set a value for self.__hash__() once so that every time
671+ # it is used this is fast. Note that in contrast to the
672+ # cached object key, the hash key needs to be unique across all
673+ # Python objects, so we include the class in the
674+ # event that different objects have the same Python value
675+ self .hash = hash ((cls , name ))
676+ return self
677+
655678 @property
656679 def is_literal (self ) -> bool :
657680 """
@@ -679,6 +702,10 @@ def is_uncertain_final_definitions(self, definitions) -> bool:
679702 """
680703 return False
681704
705+ @property
706+ def value (self ):
707+ return self ._value
708+
682709
683710def symbol_set (* symbols : Tuple [Symbol ]) -> FrozenSet [Symbol ]:
684711 """
@@ -706,7 +733,7 @@ def symbol_set(*symbols: Tuple[Symbol]) -> FrozenSet[Symbol]:
706733# PredefineSymbol.
707734
708735SymbolFalse = PredefinedSymbol ("System`False" , value = False )
709- SymbolList = PredefinedSymbol ("System`List" )
736+ SymbolList = PredefinedSymbol ("System`List" , value = list )
710737SymbolTrue = PredefinedSymbol ("System`True" , value = True )
711738
712739SymbolAbs = Symbol ("Abs" )
0 commit comments