On 8/17/05, Jacob Kaplan-Moss <[EMAIL PROTECTED]> wrote:
> 
> Howdy everyone --
> 
> I think I was the driving force behind rejecting this ticket --
> Adrian's still 50/50 as far as I know -- so let me explain why I
> don't like it.
> 
> Actually, before I do, I should say that in the end it's really
> Adrian's decision in that I'll defer to his judgement should he
> decide to change his mind.  So, don't bother trying to change my mind
> (unless you want to); if you feel strongly about this, work on
> changing his.

Doing so on IRC right now... :-) I'm answering your E-mail
point-by-point, though, for Adrian's benefit as much as for yours.

> The first problem I have with the new syntax for models is that it
> makes it unclear what's a field and what's metadata::
> 
>      class Model(meta.Model)
>          field1 = meta.CharField(...)
>          admin = meta.Admin(...)
>          field2 = meta.IntegerField(...)
> 
> Did you notice that I snuck an admin declaration in there?  Yes, I
> really "shouldn't do that", but if we allow it people will.  Because
> there's no requirement to keep all the fields together in the model
> definition, there will be mixing up and that decreases readability
> which -- for me -- is the primary reason to code in Python.

That one's taken care of by the suggestion to put *all* metadata stuff
in a "class Meta" declaration, like so:

class Model(meta.Model):
    field1 = meta.CharField(...)
    field2 = meta.IntegerField(...)
    class Meta:
        admin = meta.Admin()

Of course, you could always mix-and-match if you really want:

class Model(meta.Model):
    field1 = meta.CharField(...)
    class Meta:
        admin = meta.Admin()
    field2 = meta.IntegerField(...)

But I think the natural separation of an extra indentation layer will
tend to push the "class Meta:" down underneath all the field
definitions.

> Second, what if I want a field named "admin"?  Yes, there's an
> alternate syntax for that... but if I wanted alternate syntaxes for
> the same thing, I'd use Perl.  "There should be only one way to do
> things, and that way should be obvious."  Again, I choose to program
> in Python because I can *read* it better, not because I can *write*
> it better; when I come back to my models in a year or two I want them
> to be instantly obvious.

This is also taken care of by the "class Meta:" proposal. A field
called "admin" in the "top" model class can co-exist perfectly happily
with the "admin = meta.Admin()" declaration in class Meta.

> Third, from a semantic point of view it's just wrong.  Consider::
> 
>      class RegularOldPythonClass:
>          classVar = 14
> 
>          def __init__(self):
>              self.instanceVar = 77
> 
> In the above example, ``classVar`` is, obviously, a class member and
> ``instanceVar`` is a member of *an instance* of the class.  There's
> an important semantic distinction between instance variables and
> class variables that I don't think I need to point out to everyone.
> 
> Unfortunately, the proposed model syntax subverts this.  In the
> example above, ``field1`` is not a member of the Model class (try it
> -- ``Model.field1`` will raise an ``AttributeError``); it's a member
> of an *instance* of the ``Model`` class.  So why are we defining it
> as if it were a class variable?  On the other hand, ``fields`` *is* a
> class variable, so it makes sense to define it at the class level.

This is a valid objection, to which my only response is "But SQLObject
does it the way I'm suggesting".

Perhaps the fields *should* be class variables, as well as instance
variables? In other words, accessing Model.field1 should not raise
AttributeError at all, but should be the equivalent of accessing
Model._meta.field1? (Or however that last would be spelled). Something
to think about.

> Finally, there's the "magic" aspects of dealing with something like::
> 
>      class Model(meta.Model):
>          field = meta.CharField(...)
>          meta.ForeignKey(...)
> 
> The "unadorned" ``ForeignKey`` simply doesn't make sense if you don't
> understand the magic going on underneath, whereas a list of fields
> makes perfect sense.  I'm honestly less concerned with the crazyness
> of the code than I am with the weird and non-standard syntax.
> Nowhere else in Python does a non-assignment in a class result in a
> class member being created.

That part of the proposal, after IRC discussion, is going away, by
unanimous approval.

> In Python there's always a tension between clarity and the
> conciseness you can achieve by doing cool tricks with metaclasses.
> I'm all for getting rid of as much boilerplate code as possible --
> that's why Django exists in the first place -- but not at the expense
> of clarity.  I'd rather be more verbose and more clear than concise
> and confusing (again, if I wanted concise I'd use Perl).
> 
> So that's where I stand, and those are the arguments I gave Adrian
> when we decided not to change the syntax.  Again, I'm pretty sure
> he's still not convinced either way, and if he decides to accept the
> patch, I'm not going to complain (although I'll continue to think
> it's wrong).

I think most of your objections are based either on an incorrect
understanding of the change that's being proposed, or else on
something that's going to go away. Points 1 and 2 go away (or almost
go away) with the "class Meta:" proposal, although there's a very
valid objection that that's a little bit magic and isn't the default
Pythonic behavior. But it sure does result in clean, simple,
easy-to-read code. Not concise like Perl, but concise like Python.
Point 3 is valid, and is worth pondering. And point 4 is outdated as
of a few minutes ago.

-- 
Robin Munn
[EMAIL PROTECTED]
GPG key 0xD6497014

Reply via email to