@@ -332,57 +332,78 @@ def replace_slots(self, slots, evaluation) -> "Atom":
332332
333333
334334class Symbol (Atom , NumericOperators , EvalMixin ):
335- """
336- Note: Symbol is right now used in a couple of ways which in the
337- future may be separated.
335+ """A Symbol is a kind of Atom that acts as a symbolic variable.
338336
339- A Symbol is a kind of Atom that acts as a symbolic variable or
340- symbolic constant.
337+ All Symbols have a name that can be converted to string.
341338
342- All Symbols have a name that can be converted to string form.
339+ A Variable Symbol is a ``Symbol``` that is associated with a
340+ ``Definition`` that has an ``OwnValue`` that determines its
341+ evaluation value.
343342
344- Inside a session, a Symbol can be associated with a ``Definition``
345- that determines its evaluation value.
343+ A Function Symbol, like a Variable Symbol, is a ``Symbol`` that is
344+ also associated with a ``Definition``. But it has a ``DownValue``
345+ that is used in its evaluation.
346346
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.
347+ We also have Symbols which in contrast to Variables Symbols have
348+ a constant value that cannot change. System` True and System` False
349+ are like this.
350350
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.
351+ These however are in class PredefinedSymbol. See that class for
352+ more information.
356353
357- Note that the mathics.core.parser.Symbol works exactly this way.
354+ Symbol acts like Python's intern() built-in function or Lisp's
355+ Symbol without its modifyable property list. Here, the only
356+ attribute we care about is the value which is unique across all
357+ mentions and uses, and therefore needs it only to be stored as a
358+ single object in the system.
358359
359- This aspect may or may not be true for the Symbolic Variable use case too .
360+ Note that the mathics.core.parser.Symbol works exactly this way .
360361 """
361362
362363 name : str
363364 hash : str
364365 sympy_dummy : Any
365- defined_symbols = {}
366+
367+ # Dictionary of Symbols defined so far.
368+ # We use this for object uniqueness.
369+ # The key is the Symbol object's string name, and the
370+ # diectionary's value is the Mathics object for the Symbol.
371+ _symbols = {}
372+
366373 class_head_name = "System`Symbol"
367374
368375 # __new__ instead of __init__ is used here because we want
369376 # to return the same object for a given "name" value.
370- def __new__ (cls , name : str , sympy_dummy = None , value = None ):
377+ def __new__ (cls , name : str , sympy_dummy = None ):
371378 """
372- Allocate an object ensuring that for a given `name` we get back the same object.
379+ Allocate an object ensuring that for a given ``name`` and ``cls`` we get back the same object,
380+ id(object) is the same and its object.__hash__() is the same.
381+
382+ PredefinedSymbol's like System`True and System`False set
383+ ``value`` to something other than ``None``.
384+
373385 """
374386 name = ensure_context (name )
375- self = cls .defined_symbols .get (name , None )
387+
388+ # A lot of the below code is similar to
389+ # the corresponding for numeric constants like Integer, Real.
390+ self = cls ._symbols .get (name )
391+
376392 if self is None :
377- self = super (Symbol , cls ).__new__ (cls )
393+ self = super ().__new__ (cls )
378394 self .name = name
379395
396+ # Cache object so we don't allocate again.
397+ cls ._symbols [name ] = self
398+
380399 # 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 ))
400+ # it is used this is fast. Note that in contrast to the
401+ # cached object key, the hash key needs to be unique across *all*
402+ # Python objects, so we include the class in the
403+ # event that different objects have the same Python value.
404+ # For example, this can happen with String constants.
405+
406+ self .hash = hash ((cls , name ))
386407
387408 # TODO: revise how we convert sympy.Dummy
388409 # symbols.
@@ -395,25 +416,8 @@ def __new__(cls, name: str, sympy_dummy=None, value=None):
395416 # value attribute.
396417 self .sympy_dummy = sympy_dummy
397418
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
414419 self ._short_name = strip_context (name )
415420
416- cls .defined_symbols [name ] = self
417421 return self
418422
419423 def __eq__ (self , other ) -> bool :
@@ -634,24 +638,47 @@ def to_sympy(self, **kwargs):
634638 return sympy .Symbol (sympy_symbol_prefix + self .name )
635639 return builtin .to_sympy (self , ** kwargs )
636640
637- @property
638- def value (self ) -> Any :
639- return self ._value
640-
641641
642642class PredefinedSymbol (Symbol ):
643643 """
644- A Predefined Symbol of the Mathics system.
644+ A Predefined Symbol is a Constant Symbol of the Mathics system whose value can't
645+ be changed.
645646
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.
647+ Therefore, like say, an Integer constant, we don't need to go
648+ through Definitions to get its value.
649649
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 .
650+ As we do in numeric constants, a PredefinedSymbols Python-equivalent value not its string name
651+ but to its Python-equivalent value. For example for the predefined System`True we
652+ we can set its value to the Python ``True`` value .
653653 """
654654
655+ # Dictionary of PredefinedSymbols defined so far.
656+ # We use this for object uniqueness.
657+ # The key is the PredefinedSymbol object's name, and the
658+ # diectionary's value is the Mathics object representing that Python value.
659+ _predefined_symbols = {}
660+
661+ # We use __new__ here to unsure that two Integer's that have the same value
662+ # return the same object.
663+ def __new__ (cls , name , value ):
664+
665+ name = ensure_context (name )
666+ self = cls ._predefined_symbols .get (name )
667+ if self is None :
668+ self = super ().__new__ (cls , name )
669+ self ._value = value
670+
671+ # Cache object so we don't allocate again.
672+ self ._predefined_symbols [name ] = self
673+
674+ # Set a value for self.__hash__() once so that every time
675+ # it is used this is fast. Note that in contrast to the
676+ # cached object key, the hash key needs to be unique across all
677+ # Python objects, so we include the class in the
678+ # event that different objects have the same Python value
679+ self .hash = hash ((cls , name ))
680+ return self
681+
655682 @property
656683 def is_literal (self ) -> bool :
657684 """
@@ -679,6 +706,10 @@ def is_uncertain_final_definitions(self, definitions) -> bool:
679706 """
680707 return False
681708
709+ @property
710+ def value (self ):
711+ return self ._value
712+
682713
683714def symbol_set (* symbols : Tuple [Symbol ]) -> FrozenSet [Symbol ]:
684715 """
@@ -706,7 +737,7 @@ def symbol_set(*symbols: Tuple[Symbol]) -> FrozenSet[Symbol]:
706737# PredefineSymbol.
707738
708739SymbolFalse = PredefinedSymbol ("System`False" , value = False )
709- SymbolList = PredefinedSymbol ("System`List" )
740+ SymbolList = PredefinedSymbol ("System`List" , value = list )
710741SymbolTrue = PredefinedSymbol ("System`True" , value = True )
711742
712743SymbolAbs = Symbol ("Abs" )
0 commit comments