A proposal for attribute lookup failures

Discussion in 'Python' started by MonkeeSage, Nov 18, 2007.

  1. MonkeeSage

    MonkeeSage Guest

    Proposal:

    When an attribute lookup fails for an object, check the top-level
    (and local scope?) for a corresponding function or attribute and apply
    it as the called attribute if found, drop through to the exception
    otherwise. This is just syntactic sugar.


    Example:

    a = [1,2,3]

    a.len()
    # -> fails,
    # -> finds len() in the top-level symbol table,
    # -> applies len(a)
    # -> 3

    a.foobar()
    # -> fails,
    # -> no foobar() in scope,
    # -> raise NameError


    Benefits:

    - Uniform OO style. Top-levels can be hidden as attributes of data.
    Most of the top-level functions / constructors can be considered as
    attributes of the data; e.g., an int() representation of a string can
    be considered as _part_ of the semantics of the string (i.e., one
    _meaning_ of the string is an int representation); but doing it this
    way saves from storing the int (etc) data as part of the actual
    object. The trade-off is speed for space.

    - Ability to "add" attributes to built-in types (which is requested
    all the time!!) without having to sub-class a built-in type and
    initialize all instances as the sub-class. E.g., one can simply define
    flub() in the top-level (local?) namespace, and then use "blah".flub()
    as if the built-in str class provided flub().

    - Backwards compatible; one can use the top-level functions when
    desired. No change to existing code required.

    - Seemingly trivial to implement (though I don't know much C). On
    attribute lookup failure, simply iterate the symbol table looking for
    a match, otherwise raise the exception (like current implementation).


    Drawbacks:

    - Could hide the fact that an extra (On?) lookup on the symbol table
    is necessary for attribute lookup failure. (Maybe there could be a
    switch/pragma to enable (or disable) the functionality?)

    - As above, attribute lookup failure requires an extra lookup on the
    symbol table, when normally it would fall through directly to
    exception.

    - ???


    Disclaimer:

    I realize that very often what seems good to me, ends up being half-
    assed, backwards and generally bad. So I'd appreciate input on this
    proposition. Don't take it that I think the idea is wonderful and am
    trying to push it. I am just throwing it out there to see what may
    become of it.

    Regards,
    Jordan
    MonkeeSage, Nov 18, 2007
    #1
    1. Advertising

  2. MonkeeSage

    James Stroud Guest

    MonkeeSage wrote:
    > Proposal:
    >
    > When an attribute lookup fails for an object, check the top-level
    > (and local scope?) for a corresponding function or attribute and apply
    > it as the called attribute if found, drop through to the exception
    > otherwise. This is just syntactic sugar.
    >
    >
    > Example:
    >
    > a = [1,2,3]
    >
    > a.len()
    > # -> fails,
    > # -> finds len() in the top-level symbol table,
    > # -> applies len(a)
    > # -> 3
    >
    > a.foobar()
    > # -> fails,
    > # -> no foobar() in scope,
    > # -> raise NameError
    >
    >
    > Benefits:
    >
    > - Uniform OO style. Top-levels can be hidden as attributes of data.
    > Most of the top-level functions / constructors can be considered as
    > attributes of the data; e.g., an int() representation of a string can
    > be considered as _part_ of the semantics of the string (i.e., one
    > _meaning_ of the string is an int representation); but doing it this
    > way saves from storing the int (etc) data as part of the actual
    > object. The trade-off is speed for space.
    >
    > - Ability to "add" attributes to built-in types (which is requested
    > all the time!!) without having to sub-class a built-in type and
    > initialize all instances as the sub-class. E.g., one can simply define
    > flub() in the top-level (local?) namespace, and then use "blah".flub()
    > as if the built-in str class provided flub().
    >
    > - Backwards compatible; one can use the top-level functions when
    > desired. No change to existing code required.
    >
    > - Seemingly trivial to implement (though I don't know much C). On
    > attribute lookup failure, simply iterate the symbol table looking for
    > a match, otherwise raise the exception (like current implementation).
    >
    >
    > Drawbacks:
    >
    > - Could hide the fact that an extra (On?) lookup on the symbol table
    > is necessary for attribute lookup failure. (Maybe there could be a
    > switch/pragma to enable (or disable) the functionality?)
    >
    > - As above, attribute lookup failure requires an extra lookup on the
    > symbol table, when normally it would fall through directly to
    > exception.
    >
    > - ???
    >
    >
    > Disclaimer:
    >
    > I realize that very often what seems good to me, ends up being half-
    > assed, backwards and generally bad. So I'd appreciate input on this
    > proposition. Don't take it that I think the idea is wonderful and am
    > trying to push it. I am just throwing it out there to see what may
    > become of it.


    It would be unoriginal of me to suggest that this violates the explicit
    is better than implicit maxim. But it does.

    Also, you have picked the perfect use case for a counter argument:

    py> class NoLen(object):
    .... pass
    ....
    py> len(NoLen)
    ------------------------------------------------------------
    Traceback (most recent call last):
    File "<ipython console>", line 1, in <module>
    <type 'exceptions.TypeError'>: object of type 'type' has no len()

    So this proposal would send the interpreter through two cycles of trying
    to find the proper attribute before it failed.

    Plus, I probably haven't even raised the best arguments against it, but
    my feeling is that it has serious problems and is better left out of the
    language.

    But it is an interesting idea nonetheless.

    James


    --
    James Stroud
    UCLA-DOE Institute for Genomics and Proteomics
    Box 951570
    Los Angeles, CA 90095

    http://www.jamesstroud.com
    James Stroud, Nov 18, 2007
    #2
    1. Advertising

  3. On Nov 18, 4:07 am, MonkeeSage <> wrote:
    > Proposal:
    >
    > When an attribute lookup fails for an object, check the top-level
    > (and local scope?) for a corresponding function or attribute and apply
    > it as the called attribute if found, drop through to the exception
    > otherwise. This is just syntactic sugar.


    [...]

    > Benefits:


    [...]

    > - Backwards compatible; one can use the top-level functions when
    > desired. No change to existing code required.


    It changes how the following code executes:

    --------------------------
    def foo(x): return x.foo()
    foo(1)
    --------------------------

    * currently this raises AttributeError
    * under your proposal this code would fill the stack and raise a
    RuntimeError I guess.

    > - Seemingly trivial to implement (though I don't know much C). On
    > attribute lookup failure, simply iterate the symbol table looking for
    > a match, otherwise raise the exception (like current implementation).


    This is not a benefit!


    --
    Arnaud
    Arnaud Delobelle, Nov 18, 2007
    #3
  4. MonkeeSage

    MonkeeSage Guest

    On Nov 18, 5:27 am, James Stroud <> wrote:

    > It would be unoriginal of me to suggest that this violates the explicit
    > is better than implicit maxim. But it does.


    That's what I meant about hiding the complexity of an attribute
    failure. Though, sometimes implicit is acceptable (e.g., promotion of
    int to float by __add__ when RHS is a float). Perhaps not here though.


    > Also, you have picked the perfect use case for a counter argument:
    >
    > py> class NoLen(object):
    > ... pass
    > ...
    > py> len(NoLen)
    > ------------------------------------------------------------
    > Traceback (most recent call last):
    > File "<ipython console>", line 1, in <module>
    > <type 'exceptions.TypeError'>: object of type 'type' has no len()
    >
    > So this proposal would send the interpreter through two cycles of trying
    > to find the proper attribute before it failed.


    Ah. Good point. Hadn't thought of that.

    --------

    On Nov 18, 6:42 am, Arnaud Delobelle <> wrote:

    > It changes how the following code executes:
    >
    > --------------------------
    > def foo(x): return x.foo()
    > foo(1)
    > --------------------------
    >
    > * currently this raises AttributeError
    > * under your proposal this code would fill the stack and raise a
    > RuntimeError I guess.


    I think it would be easy enough to detect and avoid cyclic references
    like that (it's done in other instances in the language). An exception
    could be thrown in such a case. But maybe it would be more difficult
    than I imagine, leading to even further complexity (bad).

    I think that, given that it hides a complex operation (which could
    easily lead to abuse by the "unwashed masses"), and that in many cases
    multiple lookups in the symbol table would be necessary before
    termination (as in James' example above), as well as having to deal
    with cases such as you mention, perhaps it's not such a good idea.

    Off the cuff, it seemed like a nice feature (and still does, if it
    could be implemented without the drawbacks). But such is life. :)

    Regards,
    Jordan
    MonkeeSage, Nov 18, 2007
    #4
  5. MonkeeSage

    MonkeeSage Guest

    Ps. Just for kicks, here is a simple ruby 1.8 mock-up of the proposal
    (sorry for using ruby, but I don't know enough C to start hacking the
    CPython backend; I think that a higher-level example is conceptually
    clearer anyhow). Reference cycles are not detected in the example.

    #!/usr/bin/ruby

    class Object
    def method_missing(fun, *args)
    begin
    TOPLEVEL_BINDING.method(fun).call(self, *args)
    rescue
    raise(NoMethodError,
    %{undefined method `#{fun.to_s}' for "#{self}":String},
    [])
    end
    end
    end

    def myfun(s1, s2)
    s1 + s2
    end

    puts "foo".myfun("bar")
    # -> foobar

    puts 1.myfun(2)
    # -> 3

    puts "foo".nofun("baz")
    # -> ./attr_fail.rb:10: undefined method `nofun' for "foo":String
    (NoMethodError)
    MonkeeSage, Nov 18, 2007
    #5
  6. MonkeeSage

    Kay Schluehr Guest

    On 19 Nov., 00:02, MonkeeSage <> wrote:
    > Ps. Just for kicks, here is a simple ruby 1.8 mock-up of the proposal
    > (sorry for using ruby, but I don't know enough C to start hacking the
    > CPython backend; I think that a higher-level example is conceptually
    > clearer anyhow).


    No need to excuse. I think Ruby provides a nice context for discussing
    the semantics of top level "open classes". But I think those are
    entirely different than your contextual bindings. Note I find your
    proposal somewhat confusing since I expect that an attribute is
    "owned" by an object and is not an arbitrary contextual property.

    Regarding open classes in Python, what about "extension classes"?

    class +object:
    def len(self):
    return self.__len__()

    This either adds the len method to the namespace of object or it
    creates a new namespace which is associated with the namespace of
    object s.t. each object can lookup attributes in this namespace when
    default lookup fails. I'm not entirely sure about scope. I think the
    lifetime of an extension class shall be determined by the lifetime of
    the extended class and not by the scope in which the extension class
    is defined. What do you think?

    Kay

    PS. you can use EasyExtend when you want to provide a language
    extension without hacking the CPython runtime. EE was made for such
    kinds of experiments.
    Kay Schluehr, Nov 18, 2007
    #6
  7. MonkeeSage

    MonkeeSage Guest

    On Nov 18, 5:59 pm, Kay Schluehr <> wrote:

    > No need to excuse. I think Ruby provides a nice context for discussing
    > the semantics of top level "open classes". But I think those are
    > entirely different than your contextual bindings. Note I find your
    > proposal somewhat confusing since I expect that an attribute is
    > "owned" by an object and is not an arbitrary contextual property.


    I obviously like ruby as well as python, I just didn't want to turn
    the discussion into a "I can do this in ruby, can you do that in
    python" thread, so my apology was more along those lines that an
    apology for using ruby at all. :)

    As far as "ownership" of an object, that's what object abstraction is
    all about is it not? Multiple instances can "own" a method via
    polymorphic substitution, without a strict interface definition. My
    proposal simply adds a new scope within which to look for "ownership".
    Of course, there are problems with that, as noted above.

    > Regarding open classes in Python, what about "extension classes"?
    >
    > class +object:
    > def len(self):
    > return self.__len__()
    >
    > This either adds the len method to the namespace of object or it
    > creates a new namespace which is associated with the namespace of
    > object s.t. each object can lookup attributes in this namespace when
    > default lookup fails. I'm not entirely sure about scope. I think the
    > lifetime of an extension class shall be determined by the lifetime of
    > the extended class and not by the scope in which the extension class
    > is defined. What do you think?


    Sounds like a interesting approach! Worth looking into, imo.

    > PS. you can use EasyExtend when you want to provide a language
    > extension without hacking the CPython runtime. EE was made for such
    > kinds of experiments.


    Hadn't seen that before, thanks for the reference. :)

    Regards,
    Jordan
    MonkeeSage, Nov 19, 2007
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kent Johnson
    Replies:
    5
    Views:
    275
    Kent Johnson
    Nov 14, 2005
  2. Replies:
    1
    Views:
    261
    Alex Martelli
    Feb 20, 2006
  3. Gary Wilson
    Replies:
    2
    Views:
    288
    Fuzzyman
    Jun 10, 2008
  4. Ethan Furman

    instance.attribute lookup

    Ethan Furman, Oct 5, 2012, in forum: Python
    Replies:
    3
    Views:
    169
    Mark Lawrence
    Oct 6, 2012
  5. W Karas
    Replies:
    0
    Views:
    221
    W Karas
    Nov 24, 2012
Loading...

Share This Page