Function source, byte-code, function definitions: new tag method?

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

Function source, byte-code, function definitions: new tag method?

Stephan Herrmann-2
Hi,

This carries on the discussion of the "source for functions" thread:

Playing around some more with function source, bytecode, argument declarations
etc. it appears to me, that the most flexible solution is not far away:

I was down to a function "deffun" that takes as arguments a function name,
a list of arguments and a string containing the source. It is now fully in
the responsibility of this function not only to store source and compiled
function together in one tagged table (that is accessible as function aswell)-
also different styles of argument handling are now possible, eg. the
argumentlist could be a table of <name>=<type> pairs, and the "function"
tagmethod could per option decide to type check the arguments or not. 
Then I stumbled over a syntax which is not really pleasing, 
function definitions would now look like this:

deffun("myPrint", "a", "print(\"myprint says:\",a)")

-- or

deffun("anotherFunc", {a1="string", a2="number"}, 
"print('anotherFunction says:')\
print(a1,a2)"
)

Now instead of puzzling about newlines in strings etc. I really like to
suggest no new syntax but A NEW TAGMETHOD: 

-- with:
function deffun(name, arguments, body)
  ...
end
-- do:
settagmethod(tag(nil), "definefunction" definefunction)
-- such that a simple ...
function myPrint (a) 
    print("myPrint says:", a)
end
-- ... would invoke a function call similar to the above "deffun" lines.

This way we would be free to assign any semantics to a function definition
in our usual syntax. First this entails a builtin function "rawdefinefunction"
which is needed to really generate a function object which is returned
from the builtin function and can be assigned to any global or local variable.
I haven't checked all implications, on how this blends with local
functions and closures; first it appears, that a function name will now
be optional; is the name a part of the function altogether? or is it two
basic operations: defining a function (argument_list, body) and assigning
the result to some variable, table field whatsoever. So maybe it would be:

function deffun (arguments, body)
   -- build my_arguments from arguments
   local fun={source=body, func=rawdefinefunction(my_arguments, body)}
   settag(fun, funcTag)
   return fun
end
-- the "function" tagmethod (f,a) for funcTag would simply call(f.func,a)

Assignment to the global name would then be outside the scope of this 
tagmethod. For anonymous functions the parser probably uses something 
similar to "rawdefinefunction" anyway, replacing a function definition
by the function object in place.

Main applications of such a technique would probably be, to store additional
information with functions, such as:
  -- the source code
  -- argument type information
  -- modifiers? think of :

	private()
	function dontcallme () ... end

	-- which could set a flag in the function's table, that prevents
	-- calls from outside this "module"

I know, the matter is not as simple, as I advertised it. Firstly the
parser may have to be completely re-written :-). More seriously the
syntax of <argument_list> might have to be reconsidered: let 
   function a (a,b,c) body end
produce a call of the tagmethod with arguments ({a,b,c}, body). 
Wouldn't it be neat to let
   function checked {a=string, b=number} body end
invoke it with ({a="string", b="number"}, body) ???
How about evaluation of names "string", "number" in the example? Would we need:
{a="string", b="number"} 
etc.pp.

Ok, I will stop for now. Maybe this looks all too esoteric to you?

I'm eagerly awaiting comments

Stephan
--------------------------------------------------------------------------
 Stephan Herrmann
 ----------------
 Technical University Berlin
 Software Engineering Research Group
 http://swt.cs.tu-berlin.de/~stephan
 phone: ++49 30 314 73174         
--------------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

Re: Function source

Steve Dekorte-2
> Is there any way to ask Lua for the source code of a function?

Stephan Herrmann wrote:
[description of seperate table with function/source pairs]
>Does this in some way or other meet your requirements?

This is clever but I need something that will work in
all cases.

I think I need a new event in Lua something like:

  compileFunction(source, sourceFile)

Would this be difficult to add?

Steve Dekorte

Reply | Threaded
Open this post in threaded view
|

Lua Forwarding problem

Steve Dekorte-2
In reply to this post by Stephan Herrmann-2
Has anyone else implemented a Smalltalk-like forwarding mechanism with Lua?
This is different from inheritance - if an none of an object's parent
classes respond to a message, it calls that object's "forward" method
with the message as an argument.

I found a way to implement this for method calls (see below) but it
causes problems for failed variable accesses (they return a the
forward function instead of nil)

I've considered doing everything with methods, but I'm not
happy with having to do my variable set/gets with methods of
a different name or having to move variables into a subtable.

Anyone found a better way to do this?

==========================================

$debug

function inherit(table, index)
    if ( index == "parent" ) then return nil end 	-- avoid loops
    local parent = table.parent		-- access parent object

    if ( type(parent) == "table" ) then	-- see if it's a table
        return parent[index]       		-- this may call Inherit again
    else
	if ( rawgettable(table, "className") ~= nil ) then  -- see if it's an object
		forwardMethod = index; -- set the global forward method
		write("inherit - forwarding message '"..tostring(index).."'\n")
		return forward; -- neat trick, have it return our forward function
	end
	return nil
   end
end

OldIndex = setfallback("index", inherit)

function forward(forwardObject,...)
    local argCount = tableLength(arg)
    local returnValue

    write("forward("..forwardMethod..")\n");
    if ( forwardSelector == "forward" ) then return nil end -- avoid loops
    if ( forwardSelector == "className" ) then return nil end -- avoid loops

    if ( argCount == 0 ) then
	returnValue = forwardObject:forward(forwardMethod)
    end
    if ( argCount == 1 ) then
	returnValue = forwardObject:forward(forwardMethod, arg[1])
    end
    if ( argCount == 2 ) then
	returnValue = forwardObject:forward(forwardMethod, arg[1], arg[2])
    end
    if ( argCount == 3 ) then
	returnValue = forwardObject:forward(forwardMethod, arg[1], arg[2], arg[3])
    end

    forwardMethod = nil
    return returnValue
end

Reply | Threaded
Open this post in threaded view
|

Lua "..." args

Steve Dekorte-2
In reply to this post by Stephan Herrmann-2
A minor feature request.

It would be nice if, when I have a method using variable args, I
could pass those args along to another function with the "..." syntax.
Example:

function SomeObject:myMethod(blah, ...)
  return anotherObject:anotherMethod(...)
end

Instead of the uglier and more limited way:

function SomeObject:myMethod(blah, ...)
    local argCount = tableLength(arg)

    if ( argCount == 0 ) then
	return anotherObject:anotherMethod(forwardMethod)
    end
    if ( argCount == 1 ) then
	return anotherObject:anotherMethod(forwardMethod, arg[1])
    end
    if ( argCount == 2 ) then
	return anotherObject:anotherMethod(forwardMethod, arg[1], arg[2])
    end
    if ( argCount == 3 ) then
	return anotherObject:anotherMethod(forwardMethod, arg[1], arg[2], arg[3])
    end
end

Reply | Threaded
Open this post in threaded view
|

Re: Lua Forwarding problem

David Jeske-2
In reply to this post by Steve Dekorte-2
On Wed, Dec 17, 1997 at 09:43:22PM -0200, Steve Dekorte wrote:
> I found a way to implement this for method calls (see below) but it
> causes problems for failed variable accesses (they return a the
> forward function instead of nil)

Neat trick Steve.

> I've considered doing everything with methods, but I'm not
> happy with having to do my variable set/gets with methods of
> a different name or having to move variables into a subtable.
> 
> Anyone found a better way to do this?

How about passing back a "special" table instead of "table.forward".

This "special" table would be like a forwarding block, waiting for
closure. Attach tag methods to handle:

1) Function call on the "block"
    - This would call the proper "forward" function of the original table.

2) Variable get
    - Fail? Or perhaps call some unavailable variable handler on the
      original table (if available).

3) Variable set
    - create the variable in the original table and do the set. Perhaps
      informing the table (object) of a variable creation.

... you get the idea...

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

Reply | Threaded
Open this post in threaded view
|

Re: Lua "..." args

David Jeske-2
In reply to this post by Steve Dekorte-2
On Wed, Dec 17, 1997 at 09:54:38PM -0200, Steve Dekorte wrote:
> It would be nice if, when I have a method using variable args, I
> could pass those args along to another function with the "..." syntax.
> Example:

uhm... pass them along with call();


> function SomeObject:myMethod(blah, ...)
>   return anotherObject:anotherMethod(...)
> end

How about just 

function SomeObject:myMethod(blah, ...)

   -- do something to shift all the args down one to make room at
   -- args[1];

   args[1] = anotherObject.anotherMethod; -- set "self" for the call()

   return call(anotherObject.anotherMethod,args);
end

> Instead of the uglier and more limited way:
> 
> function SomeObject:myMethod(blah, ...)
>     local argCount = tableLength(arg)
> 
>     if ( argCount == 0 ) then
> 	return anotherObject:anotherMethod(forwardMethod)
>     end
>     if ( argCount == 1 ) then
> 	return anotherObject:anotherMethod(forwardMethod, arg[1])
>     end
>     if ( argCount == 2 ) then
> 	return anotherObject:anotherMethod(forwardMethod, arg[1], arg[2])
>     end
>     if ( argCount == 3 ) then
> 	return anotherObject:anotherMethod(forwardMethod, arg[1], arg[2], arg[3])
>     end
> end
> 

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

Reply | Threaded
Open this post in threaded view
|

Saving the system image

Steve Dekorte-2
In reply to this post by David Jeske-2
Anyone been looking into techiques on saving an image of a Lua
session to a file? I'd guess that Smalltalk, Self and NewtonScript
have already found solutions to this problem. Does anyone have
references or URL to tech descriptions of their solutions?

Steve Dekorte

Reply | Threaded
Open this post in threaded view
|

Re: Function source

Alan Watson-2
In reply to this post by Steve Dekorte-2
I have been thinking about writing a replacement for lua_getobjname
that scans tables recursively as well as globals. I want to use this
to print better function names in error messages.

It just occured to me that a nicer alternative would be very simple
with the kind of function method that has been discussed. What I would
do is extract the function name of a function as it is compiled, and
keep a table of these names; lua_getobjname becomes, for functions at
least, a simple table access.

Actually, I would not need quite such a general function method.
Anticipating 3.1, I could do with one that took a function name and a
closure, so that:

    function aaa         (...) ... end
    function aaa.bbb     (...) ... end
    function aaa.bbb.ccc (...) ... end

would become:

    functionmethod(function (...) ... end, "aaa")
    functionmethod(function (...) ... end, "aaa", "bbb")
    functionmethod(function (...) ... end, "aaa", "bbb", "ccc")
   
The draw backs that I can see are that functions would then never be
garbage collected and, I think, my method would never see functions
defined in pre-compiled chunks.

Just a thought.

Alan

Reply | Threaded
Open this post in threaded view
|

Re: Function source

David Jeske-2
On Sun, Dec 21, 1997 at 11:02:55AM -0200, Alan Watson wrote:
> I have been thinking about writing a replacement for lua_getobjname
> that scans tables recursively as well as globals. I want to use this
> to print better function names in error messages.

I do the same thing to print object names. I only let my search go three
levels down from "global" though. I just assume that after that it's just
more trouble than it's worth to find. You also have to be carefull about
circular links if you are going to do it recursively.

> It just occured to me that a nicer alternative would be very simple
> with the kind of function method that has been discussed. What I would
> do is extract the function name of a function as it is compiled, and
> keep a table of these names; lua_getobjname becomes, for functions at
> least, a simple table access.

Why not just change the parser/VM to store the declared function name and
argument names. Of course anonymous functions won't have names. However, I
can see this data being relevant in many situations and it shouldn't be to
hard to do. In fact, it's sort of on the road to this whole "storing
source for functions" thing. 

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

Reply | Threaded
Open this post in threaded view
|

Table declaration problem

David Jeske-2
Hello,

I have come across a problem, and I'd like to know what other people think
about it and/or if it's fixed in 3.0/3.1.

The following is valid Lua code:

a_table = {};
a_table[1] = "test";
a_table["1"] = "test string";

printTable(a_table);     -- my basic print table

output>> table: 00673608
         [number] 1  =  [string] test
         [string] 1  =  [string] test string
         2 entries


However, it's NOT possible for me to do:

> a_table = { 1 = "test string" };

However, it's NOT valid to do:

> a_table = { "test" ; 1 = "test string" };

** QUESTION *** Why can't I have "named table entries" which begin with
 numbers, knowing that they will be strings?


Of course, it _is_ valid to do:

> a_table = { "test" ; boo = "test string" };



** QUESTION *** Also, why do unnamed entries in a table have to come
   first? I find it rather cumbersome. I am using the following
   initialization "style" and i'd like to do:

   table = { list_type = "image";
             { "filename1.boo" , 10, 10, 20, 20 },
             { "filename2.boo" , 10, 10, 20, 20 }
           };

 Which is much more readable than:

   table = { {"filename1.boo" , 10, 10, 20, 20 },
             {"filename2.boo" , 10, 10, 20, 20 },
             list_type = "image"
           };

 Especially when the lists are long and you have to go looking for the
 list type.             

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

Reply | Threaded
Open this post in threaded view
|

Re: Table declaration problem

Alan Watson-2
>    table = { {"filename1.boo" , 10, 10, 20, 20 },
>              {"filename2.boo" , 10, 10, 20, 20 },
>              list_type = "image"
>            };

I'm not disputing that the restrictions on table construction seem a
little odd, but if your problem is restricted to this kind of example, 
how about:

    function image(table)
        table.list_type = "image"
        return table
    end
    
    image{
        {"filename1.boo" , 10, 10, 20, 20 },
        {"filename2.boo" , 10, 10, 20, 20 },
    }

Alan

Reply | Threaded
Open this post in threaded view
|

Re: Table declaration problem

David Jeske-2
On Mon, Dec 22, 1997 at 02:02:42AM -0200, Alan Watson wrote:
> >    table = { {"filename1.boo" , 10, 10, 20, 20 },
> >              {"filename2.boo" , 10, 10, 20, 20 },
> >              list_type = "image"
> >            };
> 
> I'm not disputing that the restrictions on table construction seem a
> little odd, but if your problem is restricted to this kind of example, 
> how about:
> 
>     function image(table)
>         table.list_type = "image"
>         return table
>     end
>     
>     image{
>         {"filename1.boo" , 10, 10, 20, 20 },
>         {"filename2.boo" , 10, 10, 20, 20 },
>     }

The whole point of using the table construction syntax (IMO) is to free
yourself from having to do programmatic setup of data. In fact this
"image" table is nested deep within a tree of tables, and it would be VERY
cumbersome to have to do something like above for every single instance.

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

Reply | Threaded
Open this post in threaded view
|

Re: Table declaration problem

David Jeske-2
In reply to this post by David Jeske-2
On Sun, Dec 21, 1997 at 11:57:19PM -0200, Luiz Henrique de Figueiredo wrote:
> since 2.5 you can write:
> 
> a_table = { [1]="test" ; ["1"] = "test string" };

Why does the syntax enforce numbered items before string items though? It
seems with the syntax you present above, there would be no confusion, even
when alternating numbered and string entries, for example:

a_table = { [1]   = "test number 1",
            ["1"] = "test string 1",
            [2]   = "test number 2",
            ["2"] = "test string 2" };

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

Reply | Threaded
Open this post in threaded view
|

Re: Table declaration problem

Roberto Ierusalimschy
> Why does the syntax enforce numbered items before string items though? It
> seems with the syntax you present above, there would be no confusion, even
> when alternating numbered and string entries,

We think it would be confusing to allow a free mix of both "record" and
"list" styles in a table construction; for instance:

a = {'a', 'b', [4]='c', 'd'}

The element 'd' should be in index 3, 4 or 5? Moreover, this free mix would
complicate the code generation. However, we are considering in Lua 3.1 to
allow the "record" part to come before the "list" part, as in:

a = {style = "picture"; 'a', 'b', 'c'}

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Table declaration problem

David Jeske-2
On Mon, Dec 22, 1997 at 12:09:29PM -0200, Roberto Ierusalimschy wrote:
> > Why does the syntax enforce numbered items before string items though? It
> > seems with the syntax you present above, there would be no confusion, even
> > when alternating numbered and string entries,
> 
> We think it would be confusing to allow a free mix of both "record" and
> "list" styles in a table construction; for instance:
> 
> a = {'a', 'b', [4]='c', 'd'}
> 
> The element 'd' should be in index 3, 4 or 5? Moreover, this free mix would
> complicate the code generation.

I understand completely with the syntax above.

> However, we are considering in Lua 3.1 to
> allow the "record" part to come before the "list" part, as in:
> 
> a = {style = "picture"; 'a', 'b', 'c'}

I think this would be a good solution. The "general" form of this could be
that you can only have one "list" part, and it must be separated from any
"record" parts by semicolons. For example:

a = { <optional list part> ; <optional record part> ; <optional list part> };

Can anyone else see any need to have multiple record parts? 

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

Reply | Threaded
Open this post in threaded view
|

Re: Table declaration problem

David Jeske-2
In reply to this post by David Jeske-2
On Mon, Dec 22, 1997 at 08:27:14AM -0200, Luiz Henrique de Figueiredo wrote:
> >> a_table = { [1]="test" ; ["1"] = "test string" };
> >
> >Why does the syntax enforce numbered items before string items though? It
> >seems with the syntax you present above, there would be no confusion, even
> >when alternating numbered and string entries, for example:
> >
> >a_table = { [1]   = "test number 1",
> >            ["1"] = "test string 1",
> >            [2]   = "test number 2",
> >            ["2"] = "test string 2" };
> 
> sorry, i wasn't clear.
> with the general syntax, there are no restritions and you can write
> exactly the form above.
> inside [...] you ca put any *expressions* such as:
> 
> a={[1+2*4]="a", [sin(34)]=12, [f(x,y,z)]=45}
> --lhf

ahh, thanks, that sounds great. Although I'll still be looking forward to
being able to put a "record" part before a "list" part as described in
another followup.

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