Michael Bayer wrote:
On May 2, 2006, at 10:13 PM, Daniel Miller wrote:
If you're interested, I have lot's of comments like this on various
parts of the SQLAlchemy API.
im sure you do, but one thorny issue of SA is that it supports multiple
programming styles, particularly in 0.2, where you can use an explicitly
maintained Connection object to execute SQL, or you can use the
"implicit" style that SA 0.1 has. I know your SQL library would only
have explicit Connection and nothing else...
You greatly misunderstand my intent. I'm only trying to make it easier to do
things explicitly when I can't live with the implicit assumptions in SA.
but SA benefits greatly from
supporting more succinct programming styles, the Python audience demands
it (as evidenced by early critiques of SA being "too hard" compared to
SQLObject, Guido's trashing of Myghty because it took more than one line
of code to programmatically call a template, etc.)
I understand you're worry here. Please understand that I don't want to take
away the implicit mode is so nice to use for experimentation or simple tasks.
But you're making it harder for me to use an explicit coding style by including
all this implicit stuff right in the core of SA.
SA would be more useful if the implicit layer was written as an optional extension with
all of it's implicit behavior explicitly documented. If someone can't live with some or
all of those assumptions, then they should be able to easily shed the implicit layer and
do stuff explicitly. There should be no "I don't do anything until you invoke a
special mod" methods cluttering up the core library (case in point
sqlalchemy.orm.session.current_session). Such methods are useless unless a mod has been
installed, and they require monkey-patching to make them work which is generally frowned
upon. I wouldn't complain if it were the only way to make it work, but there's a better
and much cleaner way to do it.
at its core, cases where a __call__() method does the same thing as an
explicit method is not a perl thing at all, its a Java thing.
I never said *that* was a perl thing. It's not a Java thing either. It's an
interface thing, which is a much more general concept that has nothing to do
with any particular language.
Just take
a look at the collections classes, where various objects need to
implement multiple interface contracts; in order to implement more than
one interface, you often need to express the same functionality with
different methods.
I understand the concept of a single object implementing more than one interface. But why should SessionContext
implement two interfaces for "session context" (i.e. one __call__() interface to be used internally by SA and
one "current" property for humans to use)? The issue here is defining a clear and consistent interface for
all "session context" objects to be used everywhere. You did not have one prior to the contribution of the
SessionContext implementation, or at least it was implied in the implementation of ScopedRegistry and I just thought
that was an implementation detail (not a formalized interface). So I came up with a convenient interface for people to
use and that happened to be a property. As I have already said, I have no problem changing the interface of
SessionContext if there is a good reason to do so. All I want is one consistent interface for all "session
context" objects.
As I indicated that the interface for a "session
context" would be just a callable, it follows logically that
SessionContext would maintain its explicit API since its clear and
consistent for applications that deal with it explicitly, and also
implements __call__() in order to conform to SA's interface contract for
"session context" objects, which does not deal with SessionContext
explicitly. its no different from a dictionary having both a keys()
and an __iter__() method.
As you mentioned, a property is a really nice, logical thing for people to use. I would argue that
it's even nicer than a callable because it supports assignment and deletion in a well-known and
easy-to-remember way. If SA internally needs a callable, then why not just use the get_current()
method of SessionContext as that callable? Or why not change the internals of SA to use the
"current" property of SessionContext instead? There's not that much to change, and then
we'd have a nice, consistent interface for all "session context" objects.
As I've already said, I object to adding a __call__() method in addition to the "current" property because it adds
confusion about the "one obvious way" to get the current session. The "reference implementation" of your
"session context" seems to be ScopedRegistry, which uses three different methods to support the functionality of the
"current" property on SessionContext. I would argue that three methods are harder to remember than a single property,
and therefore I think a property is better. Convince me that a callable is better and I will gladly change the SessionContext
interface. But please, let's just have one simple interface rather than two.
there is also an recurring undercurrent of disagreement here, which is
based on my experience that total rigid adherence to commonly "accepted"
rules is a recipe for disaster...when someone goes through my code and
only looks that it "breaks rules A, B, C", I dont consider that to be a
very deep critique. usually "the rules" are too open-ended to not be
mis-interpretable....such as, is that TMTOWTDI, or is it just an object
that needs to conform to multiple interface contracts ? Is that
"premature optimization", or is it "failure to write an algorithm in a
completely brain dead way"? is that "a global variable", or is that an
"application-scoped registry" ?
On the "global variable" vs "application-scoped registry" thing, I do have some input.
First, let's avoid euphemisms--if it's an "application-scoped registry" then it's a global in the
application by definition. I don't think I've ever argued that globals should never be used (I use them
within my own applications). I'm arguing that the choice to use globals should be left to the application
developer rather than being mandated by the library developer. That means the global current_session() method
within SA needs to go. Instead, let the application developers create and maintain their own global
SessionContext instance(s). It doesn't require any more code to use SessionContext than it does to use
current_session(). Here's an example using current_session():
# model.py
import sqlalchemy.mods.threadlocal
...
# othermodule.py
from sqlalchemy import current_session
session = current_session()
...
And an equivalent example using SessionContext:
# model.py
context = SessionContext()
...
# othermodule.py
from model import context
session = context.current
...
IMHO the second version is much more desirable because the global context is
created and maintained by the application rather than the SA library. The act
of creating a SessionContext instance is explicit and intuitive. The act of
defining and storing that context object at the module level is also explicit
and intuitive. And if the user wants to have several separate contexts it's
easily possible and intuitive as well (but not so with current_session()). The
thread-local mod is implied in all the documentation examples for 0.2;
therefore it will be used by most if not all SA users at least at first. When a
project starts to move from simple experimentation mode into a full-blown
complex project where resource management must be flexible and configurable
this will become a thorn. Trust me, I know from experience. At that point
(using the current_session() method), the user would at best be forced to
monkey-patch the session context logic in SA (undesirable) and at worst be f
orced to rewrite every piece of code that uses the current_session() method
(painful). If instead they use the SessionContext then all they need to do is
make a new implementation of SessionContext to suit their needs. Since the
global is located in their own code there is no need to monkey-patch anything
since they own it and can change it as needed.
Finally, I admit I am guilty of playing the "pythonic" card when I should have kept my
mouth shut. However, one of the central themes of Python is that "There should be one -- and
preferably only one -- obvious way to do it." This is at odds with Perl culture, and I've seen
places in SA where I've wondered why there's more than one way to do what seems to be the same
thing. These are the things I'd like to point out, not to inflate my ego, but to help make SA
easier for other Python developers to understand. If you're not interested in my input I'll gladly
take my thoughts and contributions to some other project.
~ Daniel
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users