@@ -329,57 +329,78 @@ def replace_slots(self, slots, evaluation) -> "Atom":
329
329
330
330
331
331
class Symbol (Atom , NumericOperators , EvalMixin ):
332
- """
333
- Note: Symbol is right now used in a couple of ways which in the
334
- future may be separated.
332
+ """A Symbol is a kind of Atom that acts as a symbolic variable.
335
333
336
- A Symbol is a kind of Atom that acts as a symbolic variable or
337
- symbolic constant.
334
+ All Symbols have a name that can be converted to string.
338
335
339
- All Symbols have a name that can be converted to string form.
336
+ A Variable Symbol is a ``Symbol`` that is associated with a
337
+ ``Definition`` that has an ``OwnValue`` that determines its
338
+ evaluation value.
340
339
341
- Inside a session, a Symbol can be associated with a ``Definition``
342
- that determines its evaluation value.
340
+ A Function Symbol, like a Variable Symbol, is a ``Symbol`` that is
341
+ also associated with a ``Definition``. But it has a ``DownValue``
342
+ that is used in its evaluation.
343
343
344
- We also have Symbols which are immutable or constant; here the
345
- definitions are fixed. The predefined Symbols `` True``, `` False``,
346
- and ``Null`` are like this.
344
+ We also have Symbols which in contrast to Variables Symbols have
345
+ a constant value that cannot change. System` True and System` False
346
+ are like this.
347
347
348
- Also there are situations where the Symbol acts like Python's
349
- intern() built-in function or Lisp's Symbol without its modifyable
350
- property list. Here, the only attribute we care about is the name
351
- which is unique across all mentions and uses, and therefore
352
- needs it only to be stored as a single object in the system.
348
+ These however are in class SymbolConstant. See that class for
349
+ more information.
353
350
354
- Note that the mathics.core.parser.Symbol works exactly this way.
351
+ Symbol acts like Python's intern() built-in function or Lisp's
352
+ Symbol without its modifyable property list. Here, the only
353
+ attribute we care about is the value which is unique across all
354
+ mentions and uses, and therefore needs it only to be stored as a
355
+ single object in the system.
355
356
356
- This aspect may or may not be true for the Symbolic Variable use case too .
357
+ Note that the mathics.core.parser.Symbol works exactly this way .
357
358
"""
358
359
359
360
name : str
360
361
hash : str
361
362
sympy_dummy : Any
362
- defined_symbols = {}
363
+
364
+ # Dictionary of Symbols defined so far.
365
+ # We use this for object uniqueness.
366
+ # The key is the Symbol object's string name, and the
367
+ # diectionary's value is the Mathics object for the Symbol.
368
+ _symbols = {}
369
+
363
370
class_head_name = "System`Symbol"
364
371
365
372
# __new__ instead of __init__ is used here because we want
366
373
# to return the same object for a given "name" value.
367
- def __new__ (cls , name : str , sympy_dummy = None , value = None ):
374
+ def __new__ (cls , name : str , sympy_dummy = None ):
368
375
"""
369
- Allocate an object ensuring that for a given `name` we get back the same object.
376
+ Allocate an object ensuring that for a given ``name`` and ``cls`` we get back the same object,
377
+ id(object) is the same and its object.__hash__() is the same.
378
+
379
+ SymbolConstant's like System`True and System`False set
380
+ ``value`` to something other than ``None``.
381
+
370
382
"""
371
383
name = ensure_context (name )
372
- self = cls .defined_symbols .get (name , None )
384
+
385
+ # A lot of the below code is similar to
386
+ # the corresponding for numeric constants like Integer, Real.
387
+ self = cls ._symbols .get (name )
388
+
373
389
if self is None :
374
- self = super (Symbol , cls ).__new__ (cls )
390
+ self = super ().__new__ (cls )
375
391
self .name = name
376
392
393
+ # Cache object so we don't allocate again.
394
+ cls ._symbols [name ] = self
395
+
377
396
# Set a value for self.__hash__() once so that every time
378
- # it is used this is fast.
379
- # This tuple with "Symbol" is used to give a different hash
380
- # than the hash that would be returned if just string name were
381
- # used.
382
- self .hash = hash (("Symbol" , name ))
397
+ # it is used this is fast. Note that in contrast to the
398
+ # cached object key, the hash key needs to be unique across *all*
399
+ # Python objects, so we include the class in the
400
+ # event that different objects have the same Python value.
401
+ # For example, this can happen with String constants.
402
+
403
+ self .hash = hash ((cls , name ))
383
404
384
405
# TODO: revise how we convert sympy.Dummy
385
406
# symbols.
@@ -392,25 +413,8 @@ def __new__(cls, name: str, sympy_dummy=None, value=None):
392
413
# value attribute.
393
414
self .sympy_dummy = sympy_dummy
394
415
395
- # This is something that still I do not undestand:
396
- # here we are adding another attribute to this class,
397
- # which is not clear where is it going to be used, but
398
- # which can be different to None just three specific instances:
399
- # * ``System`True`` -> True
400
- # * ``System`False`` -> False
401
- # * ``System`Null`` -> None
402
- #
403
- # My guess is that this property should be set for
404
- # ``PredefinedSymbol`` but not for general symbols.
405
- #
406
- # Like it is now, it looks so misterious as
407
- # self.sympy_dummy, for which I have to dig into the
408
- # code to see even what type of value should be expected
409
- # for it.
410
- self ._value = value
411
416
self ._short_name = strip_context (name )
412
417
413
- cls .defined_symbols [name ] = self
414
418
return self
415
419
416
420
def __eq__ (self , other ) -> bool :
@@ -631,24 +635,59 @@ def to_sympy(self, **kwargs):
631
635
return sympy .Symbol (sympy_symbol_prefix + self .name )
632
636
return builtin .to_sympy (self , ** kwargs )
633
637
634
- @property
635
- def value (self ) -> Any :
636
- return self ._value
637
-
638
638
639
- class PredefinedSymbol (Symbol ):
639
+ class SymbolConstant (Symbol ):
640
640
"""
641
- A Predefined Symbol of the Mathics system.
641
+ A Symbol Constant is Symbol of the Mathics system whose value can't
642
+ be changed and has a corresponding Python representation.
642
643
643
- A Symbol which is defined because it is used somewhere in the
644
- Mathics system as a built-in name, Attribute, Property, Option,
645
- or a Symbolic Constant.
644
+ Therefore, like an ``Integer`` constant such as ``Integer0``, we don't
645
+ need to go through ``Definitions`` to get its Python-equivalent value.
646
646
647
- In contrast to Symbol where the name might not have been added to
648
- a list of known Symbol names or where the name might get deleted,
649
- this never occurs here.
647
+ For example for the ``SymbolConstant`` ``System`True``, has its
648
+ value set to the Python ``True`` value.
649
+
650
+ Note this is not the same thing as a Symbolic Constant like ``Pi``,
651
+ which doesn't have an (exact) Python equivalent representation.
652
+ Also, Pi *can* be Unprotected and changed, while True, cannot.
653
+
654
+ Also note that ``SymbolConstant`` differs from ``Symbol`` in that
655
+ Symbol has no value field (even when its value happens to be
656
+ representable in Python. Symbols need to go through Definitions
657
+ get a Symbol's current value, based on the current context and the
658
+ state of prior operations on that Symbol/Definition binding.
659
+
660
+ In sum, SymbolConstant is partly like Symbol, and partly like
661
+ Numeric constants.
650
662
"""
651
663
664
+ # Dictionary of SymbolConstants defined so far.
665
+ # We use this for object uniqueness.
666
+ # The key is the SymbolConstant's value, and the
667
+ # diectionary's value is the Mathics object representing that Python value.
668
+ _symbol_constants = {}
669
+
670
+ # We use __new__ here to unsure that two Integer's that have the same value
671
+ # return the same object.
672
+ def __new__ (cls , name , value ):
673
+
674
+ name = ensure_context (name )
675
+ self = cls ._symbol_constants .get (name )
676
+ if self is None :
677
+ self = super ().__new__ (cls , name )
678
+ self ._value = value
679
+
680
+ # Cache object so we don't allocate again.
681
+ self ._symbol_constants [name ] = self
682
+
683
+ # Set a value for self.__hash__() once so that every time
684
+ # it is used this is fast. Note that in contrast to the
685
+ # cached object key, the hash key needs to be unique across all
686
+ # Python objects, so we include the class in the
687
+ # event that different objects have the same Python value
688
+ self .hash = hash ((cls , name ))
689
+ return self
690
+
652
691
@property
653
692
def is_literal (self ) -> bool :
654
693
"""
@@ -676,6 +715,10 @@ def is_uncertain_final_definitions(self, definitions) -> bool:
676
715
"""
677
716
return False
678
717
718
+ @property
719
+ def value (self ):
720
+ return self ._value
721
+
679
722
680
723
def symbol_set (* symbols : Tuple [Symbol ]) -> FrozenSet [Symbol ]:
681
724
"""
@@ -689,10 +732,10 @@ def symbol_set(*symbols: Tuple[Symbol]) -> FrozenSet[Symbol]:
689
732
690
733
# Symbols used in this module.
691
734
692
- # Note, below we are only setting PredefinedSymbol for Symbols which
735
+ # Note, below we are only setting SymbolConstant for Symbols which
693
736
# are both predefined and have the Locked attribute.
694
737
695
- # An experiment using PredefinedSymbol ("Pi") in the Python code and
738
+ # An experiment using SymbolConstant ("Pi") in the Python code and
696
739
# running:
697
740
# {Pi, Unprotect[Pi];Pi=4; Pi, Pi=.; Pi }
698
741
# show that this does not change the output in any way.
@@ -702,9 +745,9 @@ def symbol_set(*symbols: Tuple[Symbol]) -> FrozenSet[Symbol]:
702
745
# more of the below and in systemsymbols
703
746
# PredefineSymbol.
704
747
705
- SymbolFalse = PredefinedSymbol ("System`False" , value = False )
706
- SymbolList = PredefinedSymbol ("System`List" )
707
- SymbolTrue = PredefinedSymbol ("System`True" , value = True )
748
+ SymbolFalse = SymbolConstant ("System`False" , value = False )
749
+ SymbolList = SymbolConstant ("System`List" , value = list )
750
+ SymbolTrue = SymbolConstant ("System`True" , value = True )
708
751
709
752
SymbolAbs = Symbol ("Abs" )
710
753
SymbolDivide = Symbol ("Divide" )
0 commit comments