By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,818 Members | 1,282 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,818 IT Pros & Developers. It's quick & easy.

A proposal for attribute lookup failures

P: n/a
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
Nov 18 '07 #1
Share this Question
Share on Google+
4 Replies


P: n/a
On Nov 18, 4:07 am, MonkeeSage <MonkeeS...@gmail.comwrote:
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

Nov 18 '07 #2

P: n/a
On Nov 18, 5:27 am, James Stroud <jstr...@mbi.ucla.eduwrote:
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:

pyclass NoLen(object):
... pass
...
pylen(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 <arno...@googlemail.comwrote:
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
Nov 18 '07 #3

P: n/a
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)
Nov 18 '07 #4

P: n/a
On 19 Nov., 00:02, MonkeeSage <MonkeeS...@gmail.comwrote:
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.

Nov 19 '07 #5

This discussion thread is closed

Replies have been disabled for this discussion.