upvalues and polymorphism

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

upvalues and polymorphism

Dan Marks
I hate to stray more toward the Python crowd, but
I couldn't help noticing that upvalues seem like
a way to introduce object-oriented like programming
capability into lua.  So the question is, why not
then make it so one is able to define functions that
are called differently depending on the tag of the
first parameter.  

For example, I could define 

myclass = newclass()   -- really would be a "newtag"
myclass = newclass(oldclass) -- same as newtag() except all
          -- methods would be copied from the old class.
e = myclass(5,4,6)  -- would call constructor method for myclass 
            -- with parameters 5,4,6

then I could define a function like

function myclass:mymethod(a,b,c)
local x,y,z
 ...
end

To be invoked as e.mymethod(5,6,7)

You could even have constructors/destructors like

function myclass
local x,y,z

end

or function ~myclass
  (called during garbage collection)

Perhaps I am missing the point on how upvalues should
be used, but it seems to me that invoking methods by
data type is a very common occurrence in most languages,
and lua is an excellent candidate to have good polymorphism.
Tags and classes are already almost analogous, and maybe
there is a simple way to make this work.  I guess
"automatic upvalues" would be like inheritance, and would
facilitate calling subclassed methods, etc.

I don't want to turn lua in to a scripted C++ but lua
would be a very powerful and compact object-oriented 
language.  I think lua's strength is its simplicity so
if these types of features could be added without language
bloat that would be a great thing.

Dan

Daniel Marks
[hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: upvalues and polymorphism

Luiz Henrique de Figueiredo
>From [hidden email] Fri May 15 01:10:23 1998
>
>I hate to stray more toward the Python crowd, but
>I couldn't help noticing that upvalues seem like
>a way to introduce object-oriented like programming
>capability into lua.

no, upvalues are ways to create anonymous functions with different internal
constants, or in other words, functions with their own enclosing environment.
if you have to label it, upvalues and anonymous functions go more towards
functional programming than towards object-oriented programming.
tag methods on the other hand, do help in implementing object-oriented stuff.

>So the question is, why not
>then make it so one is able to define functions that
>are called differently depending on the tag of the
>first parameter.  

this is possible already.
just model objects with tables. then o:f(x,y,z)is sugar for o.f(o,x,y,z)
and you can do whatever you want to create a function value for o.f.
this uses tags methods, of course.

>For example, I could define 
>
>myclass = newclass()   -- really would be a "newtag"
>myclass = newclass(oldclass) -- same as newtag() except all
>          -- methods would be copied from the old class.

function newclass(old)
	new=newtag()
	if old then copytagmethods(old,new) end
	return new
end

copytagmethods is new in 3.1. in previous versions, you can explicitly copy all
methods needed with settagmethod(new,gettagmethod(old,x),x)

>e = myclass(5,4,6)  -- would call constructor method for myclass 
>            -- with parameters 5,4,6

ok, then you want newclass above to create and returna a table, set its tag
and also set the "function" tag method so that you trap this.

>then I could define a function like
>
>function myclass:mymethod(a,b,c)
>local x,y,z
> ...
>end
>
>To be invoked as e.mymethod(5,6,7)

can't you do this already?

>You could even have constructors/destructors like
>
>function myclass
>local x,y,z
>
>end
>
>or function ~myclass
>  (called during garbage collection)

if you must use C++ syntax, then ok, all this can be done with tag methods,
except for using ~myclass.

>Perhaps I am missing the point on how upvalues should
>be used,

like I said, upvalues are not really the point here, althoug they could be
useful too.

>but it seems to me that invoking methods by
>data type is a very common occurrence in most languages,

sure, and that's why we have tag methods in Lua.
granted, using tag methods can get complicated sometimes, depending on what
you really want to do. the point is that many things that seem to depend on
a language change are already possible with tag methods.

>I don't want to turn lua in to a scripted C++ but lua

good! :-)

>language.  I think lua's strength is its simplicity so
>if these types of features could be added without language
>bloat that would be a great thing.

I agree 100%. To quote our home page:

 A fundamental concept in the design of Lua is to provide
 <EM>meta-mechanisms</EM> for implementing features, instead of
 providing a host of features directly in the language.  For example,
 although Lua is not a pure object-oriented language, it does provide
 meta-mechanisms for implementing classes and inheritance.

 Lua's meta-mechanisms bring an economy of concepts and keep the
 language small, while allowing the semantics to be extended in
 unconventional ways.  Extensible semantics is a distinguishing feature
 of Lua.

 The implementation goals are simplicity, efficiency, portability, and
 low embedding cost.

--lhf

Reply | Threaded
Open this post in threaded view
|

Re: upvalues and polymorphism

David Jeske-2
In reply to this post by Dan Marks
On Fri, May 15, 1998 at 01:10:49AM -0300, Dan Marks wrote:
> I hate to stray more toward the Python crowd, but
> I couldn't help noticing that upvalues seem like
> a way to introduce object-oriented like programming
> capability into lua.  So the question is, why not
> then make it so one is able to define functions that
> are called differently depending on the tag of the
> first parameter.  

Lua already has OO like programming capability which is very much like
what you are talking about here, in fact, better.

> For example, I could define 
> 
> myclass = newclass()   -- really would be a "newtag"
> myclass = newclass(oldclass) -- same as newtag() except all
>           -- methods would be copied from the old class.
> e = myclass(5,4,6)  -- would call constructor method for myclass 
>             -- with parameters 5,4,6
> 
> then I could define a function like
> 
> function myclass:mymethod(a,b,c)
> local x,y,z
>  ...
> end
> 
> To be invoked as e.mymethod(5,6,7)

If you look through some of the online papers about Lua, there is already
a prototype based behavior inheritence system which acts just like this.

except the involking occurs as:

e:mymethod(5,6,7)

In fact, in lua that is just a shortcut for:

e.mymethod(e,5,6,7);

and "function myclass:mymethod(a,b,c)" is just a shortcut for:

function mymethod_temp(this,a,b,c) 
[function body]
end;

myclass.mymethod = mymethod;
mymethod_temp = nil;

> You could even have constructors/destructors like
> 
> function myclass
> local x,y,z
> 
> end
> 
> or function ~myclass
>   (called during garbage collection)

Is there a tag method for garbage collection? If so, you can already do
this. (i.e. setup the tag method for a table to call it's internal
destructor)

> Perhaps I am missing the point on how upvalues should
> be used, but it seems to me that invoking methods by
> data type is a very common occurrence in most languages,
> and lua is an excellent candidate to have good polymorphism.
> Tags and classes are already almost analogous, and maybe
> there is a simple way to make this work.  I guess
> "automatic upvalues" would be like inheritance, and would
> facilitate calling subclassed methods, etc.

I think the bigger question to ask is why table operations and tag methods
are different. Namely, why isn't syntax execution defined as a table
access, and thus all values would be tables.

For example, "foo(1,2,3)" would trigger the evaluator:

foo.function(1,2,3);

whereas "foo[1]" would trigger the evaluator:

foo.array(1);

and "foo = bar" would trigger the evaluator:

foo.assign(bar);

-----------------------

Perhaps this isn't a good idea, or dosn't buy us much. However, if the
idea were to unify everything under some concept, I would far sooner think
the general concept of tables would unify everything, than the
upvalue/tagmethod concept.

> I don't want to turn lua in to a scripted C++ but lua
> would be a very powerful and compact object-oriented 
> language.  I think lua's strength is its simplicity so
> if these types of features could be added without language
> bloat that would be a great thing.

I'll just reiterate that I have a prototype based inheritence system in
use in a project right now. It works just like the "parent" inheritence
example in one of the Lua papers. You can construct objects, and they
inherit behavior. It works just like you are talking about here.

If I was going to add something to Lua, I'd spend my time trying to do
some sort of table lookup cache, as currently using multiple levels of
tables for orginization (either as classes, or just as heirarchy) costs.
In fact, for this specific reason, I'd like to see the "lookup" VM codes
dereference a complete table lookup, instead of just one slot. It would be
much more efficient to come up with a cache method for: 

PUSHTABLE    foo
TABLELOOKUP  bar.joe.frank

than it is to optimize:

PUSHTABLE foo
TABLELOOKUP bar
TABLELOOKUP joe
TABLELOOKUP frank

Am I wrong in assuming that table lookup is somewhat costly in lua?


-- 
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: upvalues and polymorphism

Luiz Henrique de Figueiredo
In reply to this post by Dan Marks
>From [hidden email] Fri May 15 15:30:25 1998
>
>I think the bigger question to ask is why table operations and tag methods
>are different. Namely, why isn't syntax execution defined as a table
>access, and thus all values would be tables.
>
>For example, "foo(1,2,3)" would trigger the evaluator:
>
>foo.function(1,2,3);
>
>whereas "foo[1]" would trigger the evaluator:
>
>foo.array(1);
>
>and "foo = bar" would trigger the evaluator:
>
>foo.assign(bar);

This is almost exactly what Lua does right now.
You can set tag methods to catch all these.
They are called "function", "gettable", "setglobal", ...

>Perhaps this isn't a good idea, or dosn't buy us much. However, if the
>idea were to unify everything under some concept, I would far sooner think
>the general concept of tables would unify everything, than the
>upvalue/tagmethod concept.

You're right.
The rationale is that whenever you want to do something special, put a
table around the objects you want to handle and set tag methods to catch
the operations done to the objects.
This is what a "meta-mechanism" is all about.

>If I was going to add something to Lua, I'd spend my time trying to do
>some sort of table lookup cache, as currently using multiple levels of
>tables for orginization (either as classes, or just as heirarchy) costs.

Really? Table lookup should take constant time.
Do you have hard data on performance costs? We'd be interested...

>In fact, for this specific reason, I'd like to see the "lookup" VM codes
>dereference a complete table lookup, instead of just one slot. It would be
>much more efficient to come up with a cache method for: 
>
>PUSHTABLE    foo
>TABLELOOKUP  bar.joe.frank
>
>than it is to optimize:
>
>PUSHTABLE foo
>TABLELOOKUP bar
>TABLELOOKUP joe
>TABLELOOKUP frank

That would be something like "with" in Pascal.
Right, this would be slightly more efficient, but like I said, table lookup
should take constant time. So we're tlking about .1 msec vs .3 msec :-)
This is a reasonable suggestion but would require adding a "with" construct.

>Am I wrong in assuming that table lookup is somewhat costly in lua?

Yes. Table lookup should take constant time because it's based on hashing.
What costs did you have in mind?
--lhf

Reply | Threaded
Open this post in threaded view
|

Re: upvalues and polymorphism

Roberto Ierusalimschy
In reply to this post by David Jeske-2
> In fact, for this specific reason, I'd like to see the "lookup" VM codes
> dereference a complete table lookup, instead of just one slot. It would be
> much more efficient to come up with a cache method for:
> 
> ...
> 
> Am I wrong in assuming that table lookup is somewhat costly in lua?

As lhf aswered, table lookup takes constant time in Lua. The constant can be
a little heavy, but not too much... Just in case, it is important to remember
that, in critical cases, a local variable can be explicitly used to "cache"
table lookups. As a tipical example, the following loop

      local i = 1
      while i<=MAX do
        obj:f(a.b.c.d[i])
        i = i+1
      end

can be rewritten as

      local i = 1
      local t = a.b.c.d
      local f = obj.f
      while i<=MAX do
        f(obj, t[i])
        i = i+1
      end

with good impact on performance.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: upvalues and polymorphism

Steve Dekorte-2
>local i = 1
>while i<=MAX do
>obj:f(a.b.c.d[i])
>i = i+1
>end
>
>can be rewritten as
>
>local i = 1
>local t = a.b.c.d
>local f = obj.f
>while i<=MAX do
>f(obj, t[i])
>i = i+1
>end

Assumming f doesn't effect a, b, c or d, of course.

Steve