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