I agree that C is probably not necessary, and really is not necessary
to be included in "from sympy import *". So I'm +1 to remove it,
unless we determine that it really is needed. Should we deprecate it
first, or just remove it?

S on the other hand is quite useful. Because the members are
singletonized, you can use "is" comparison (much faster than ==
comparison). But this only works if you have the element itself, so
for example, if you want to compare against 0, you have to first
sympify 0.  "a is S.Zero" is the cleanest way to do this. I'm also
rather fond of the tab-completeable shortcut for 1/2 by S.Half in
interactive use.

Also, unlike C, S only eats up those objects that specifically set it
as their metaclass. So the name clash issue that Ronan mentioned does
not apply. I also seriously doubt any external code uses S to create
its own singletons, though something like that would be perfectly
acceptable and supported, so long as the names don't clash with
existing names.

Aaron Meurer

On Sep 28, 2012, at 12:06 PM, Ronan Lamy <[email protected]> wrote:

> Le vendredi 28 septembre 2012 à 09:13 +0200, Joachim Durchholz a écrit :
>> Hi all,
>>
>> I'm having some trouble with S and C and would like to find out the root
>> cause, and which ways to deal with that are available.
>>
>> The basic situation is that S and C do not show their members in the
>> source code, the members are created dynamically during import.
>> This is a nifty usage of Python's dynamic features, but it's giving code
>> analysis tools a really hard time.
>> For example, for every occurrence of C.<whatever> in SymPy, Eclipse
>> Pydev spits out a warning that C.<whatever> isn't present in class C.
>> Last time I ran that check, that was a four-digit number of warnings.
>>
>> This in itself wouldn't be a problem. Pydev allows suppressing specific
>> kinds of warnings.
>> However, suppressing warnings can hide real problems. E.g. if a member
>> of C is renamed/removed during refactoring, but there's still a
>> reference to it somewhere inside SymPy, and unit tests happen to miss
>> the situation that would trigger the error.
>
> There is another problem: C is a flat, global namespace, which makes
> name collisions likely. Worse, these collisions can happen behind the
> scenes, causing spooky action at a distance - for instance:
>
>>>> trigsimp(cos(x)**2 + sin(x)**2)
> 1
>>>> c = Function('cos')
>>>> trigsimp(cos(x)**2 + sin(x)**2)
> sin(x)**2 + cos(x)**2
>
> (what happened is that Function('cos') registered C.cos = c, but
> trigsimp relies on C.cos == cos ...)
>
>>
>> For this reason, I'd like to eliminate the irrelevant warnings.
>>
>> There are two issues that are blocking me from moving forward with this:
>>
>> 1) I do not fully understand what C and S actually do.
>> C says that it is needed to avoid problems with cyclic imports, but it
>> does not describe what the problem exactly is, or how having C avoids
>> those problems.
>
> C is used to gain access to a class without importing the module where
> it's defined - which prevents a cyclic import if that module imports the
> current one. However, doing the import at function/module-level would
> solve the issue just as well.
>
>> For S, it's similar to C but not saying anything about cyclic imports,
>> so I'm wondering if that's just not documented or whether S does indeed
>> serve a different purpose than C. S' purpose also remains unclear - it's
>> a singleton mechanism, I can see that easily, but if it's just an
>> implementation vehicle, I don't understand why all singletons are made
>> into members of S - the construction should rather be that S provides
>> the singleton machinery and classes that need a singleton use a member
>> that's a subclass of S.
>
> S registers all singleton instances, but it's not an essential part of
> the implementation of singletons. It should really be thought of as a
> simple dictionary that happens to use the nicer attribute access syntax
> "S.foo" instead of the usual item access syntax "S['foo']".
>>
>> 2) I'm not sure how C and S are being used "in the wild", so I don't
>> know which kinds of publicly visible changes will break code of SymPy
>> users. This makes it hard to decide how to fix the problem, or whether
>> fixing it is even worth the potential breakage.
>
> I suspect that C isn't used much, but S is probably used, due to the
> existence of S() as a shortcut for sympify() and to the fact that S.One
> looks like the nicest way of accessing the One() singleton.
>
> In any case, changing or removing them would require a significant
> deprecation period.
>
>> Here's a short list of approaches that could be explored. I'd like to
>> know what you people think about each:
>>
>> a) Turn S into a pure implementation vehicle, making S instances into
>> hidden members of all classes that need a singleton.
>> I think some initialization code populates S with singletons that are
>> available to user code, so that would break a lot of user code. It would
>> be the conceptually cleanest approach for S (if S was indeed intended to
>> be just an implementation vehicle).
>>
>> b) Eliminate C, solve the import cycle problems in some other way (one
>> could shortcut the second invocation of the import, or the cyclic
>> dependency could be factored out into a separate module that's imported
>> by all classes that are part of the cycle).
>
> More simply, it should be the case that every use of C.* can be replaced
> by a function-level import (because by the time 'C.Foo' is executed, Foo
> must have been defined, which means that its module has been imported by
> the interpreter already). Of course, it's better to move the import to
> the top of the module whenever possible.
>
>> This could break huge amounts of user code because people tend to use
>> C.<whatever>. It would require changing all the call sites to C inside
>> SymPy itself (something I'm willing to do so, sacrifices must be made).
>
> Thanks for offering to do it. That would be very useful.
>>
>> C) Make sure each member exists as source code.
>> E.g. extend C and S with a stub for each member that gets introduced by
>> some other module. The stub just throws an exception that says "Please
>> import module Foo to use C.bar" so that people get meaningful error
>> messages if they forget to import something that should have populated C
>> (or S).
>> This adds another clerical task on anybody who wishes to extend C or S
>> with a new member. On the other hand, it will give them a heads-up if
>> they create a name conflict, or make them look whether what they're
>> adding isn't already available under a slightly different name, so it
>> can be argued that that's not just bad.
>
> Let's not do that. Just not. Please!
>
>> D) Leave everything as it is, declaring it's not worth it.
>
> Given the problems with C, I think we should really do something about
> it. Dealing with S is probably worth it as well, but less of a priority,
> I think.
>>
>> Obviously, I would like to do something else than D, but I need input to
>> decide whether that's actually a good idea and whether it should be A+B
>> or C, or something else altogether.
>>
>> Thoughts? Comments?
>>
>> Regards,
>> Jo
>>
>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group at 
> http://groups.google.com/group/sympy?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sympy?hl=en.

Reply via email to