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

Reply via email to