[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: "static" declaration

Jeremy Hylton writes:
> >>>>> "DW" == Dan Weinreb <dlw@smartleaf.com> writes:
>   DW> there is no place I can look to find the answer to the
>   DW> question "what are the instance variables of this class",
>   DW> since any imperative method anywhere is free to just add a new
>   DW> one at any time.  So I am forced to trace through all the
>   DW> imperative paths in order to be able to draw my nice little
>   DW> notes in my notebook that say what the classes are and what
>   DW> their instance variables are.
> I have been wondering, as this thread progresses, why do you want to
> have a notes that say what the instance variables of classes are?  I
> don't mean to deride the need for these notes.  Rather, I'm wondering:
> Why I haven't been bothered by the lack of declarations for instance
> variables in Python classes.  Conversely, what about Perl makes the
> lack of declarations a nuisance?

Perl's philosophy is to have sensible defaults; consequently, if you
try to fetch a hash item (Perl calls associative arrays hashes) that
doesn't exist, it returns undef (Perl's equivalent to NULL.), and
undef acts like an empty string or 0 in string and numeric contexts.
(Although it gives you a warning.)

Python's philosophy is to refuse to guess in the face of ambiguity;
consequently, attempting to apply a string or numeric operation to
None (Python's NULL) raises an exception, and so does trying to
retrieve a dict item (Python calls associative arrays dicts) that
doesn't exist.

In both languages, instance variables are typically stored in an
associative array.  So, in Perl, reading a nonexistent instance
variable gives you undef, while in Python, it raises an exception.

Since NULL is a sensible initial value for many instance variables,
Perl constructors don't need to mention those instance variables, but
Python __init__ functions (I can't call them constructors anymore,
dammit) often need to.

There are cases where one instance variable is only meaningful if
another one has a non-default value, and in those cases, it's safe to
leave them uninitialized in the constructor and then add them later.
For example, a UTF-8 decoder in C I was playing with the other day has
a "constructor" like this:

decoding_state *new_decoding_state() {
  decoding_state *x = malloc(sizeof(*x));
  if (x) {
    x->len = 0;
    x->ucs = 0xdeadbeef; /* undefined unless len != 0 */
    x->min = 0xdeadbeef; /* likewise */
  return x;

In this case, not setting the attributes in the constructor, and
getting an exception if they're accessed without setting len first ---
is preferable to setting them to some bogus value.

But the more usual case is that all instance variables are
well-defined at all times after __init__ has run.

> It seems that knowing the complete set of instance variables is, by
> itself, rather uninteresting.  

But if that's what you want, perl -lne 'print $2 while
/\$(this|self)->\{(.*?)}/g' | sort -u does a pretty good job as long
as the code you're looking at follows normal Perl conventions (and
doesn't generate Perl modules).

With regard to Dan's original problem, by the way, I usually determine
whether a Perl function is intended to be a class method or an object
method by whether its first parameter is called "$class" or "$this" or
"$self"; it's slightly less visually clear than "static", and it's
only a convention, but it works pretty well most of the time.

I prefer that languages have facilities for expressing things like
this rather than having to fall back on convention.

> It's clear that eggs() is a method, because it is defined in a class.
> _state must be an instance variable since it's an attribute of state,
> while arg is a local variable.  (It's also clear that eggs() isn't a
> static or class method, because those are defined differently.)

In old Python, it's even better: it's clear that eggs() isn't a static
or class method because no such thing exists.  I think you're
overselling the new way of doing things, which is to put "eggs =
staticmethod(eggs)" somewhere after the end of the method definition
(conventionally, immediately after it).

<kragen@pobox.com>       Kragen Sitaker     <http://www.pobox.com/~kragen/>
Edsger Wybe Dijkstra died in August of 2002.  This is a terrible loss after 
which the world will never be the same.