Newsgroups: comp.lang.perl,comp.lang.tcl
Date: Tue, 13 Oct 92 01:26:24 EDT
From: thayer@cs.columbia.edu (Charles Thayer)
Subject: ObjOriented perl, dynamic Loading of C code for perl in tcl

Such a short message, such confusion, oops... Here's a better explanation.

me> sub foo {
me>   local($a,$b,$c)=@_;
me>   print "$c\n";
me>   return ["$a $b"];
me> }

tc> Current thinking holds that ["$a $b"] would be a pointer to 
tc> a list containing one element, the string "$a $b", like
tc>     \( "$a $b" )
tc> or using the function=call syntax
tc>     ref ("$a $b")
tc> Although I get nervous about the function-call syntax.
tc> Let's see now, are you talking about 
tc>     &{$a}($b);
tc> That is, call the function whose name is in $a with the argument $b?
tc> How can you tell the name?

I was simply talking about &ref("$a $b"); which you mention first, not
the fancier &{$a}($b);  Here is the perl version:

$a="foo";
$b="bar";
["$a $b"];	==>  &ref('foo bar');
[$a $b];	==>  &ref('$a $b');

me> the '["$a $b"]' would call a user-written c-subroutine (see your usub
me> dir of the perl source.)

By this I simply mean you'd have the following code in 
perl/usub/moop.mus:

	moop_init()
	...
	    make_usub("moop", US_moop, usersub, filename);
	...
	usersub()
	...
	    switch (ix) {
	CASE char* moop
	I	char*		s
	END
	...

And in perl/usub/usersub.c:

	int userinit() { init_moop(); ...; }

moop() would be the implementation, in C, of &ref which you mention
above.  It's job is to provide a blunt entry point for arbitrary code
on the part of software toolers who write C code and recompile their
own versions of perl.  moop() is implemented in C and calls perl
routines by using the function callv() in perl/usub/usersub.c

[incidentally, do you have any sample code that uses callv(), or
callback()?  I have only been able to find mus examples.]

char *moop(char *s) is a very simple interface, in a little farther down
I will explain what I'd like it to do.

tc> Generalizing the dbm access routines so you could get at arbitrary 
tc> functions through associative arrays references is someone related
tc> to this.

I have no idea what you mean, but I did once try to write a small
object-oriented system for perl using strictly associative arrays as
symbol tables.  It was rudimentary but has helped me form to my
current opinions.  The methods in the system were simply strings that
got eval'ed if invoked on an object, and objects were stored in
another associative array.  The messaging routine was stored as a 
string also, so it was rewritable by objects themselves.  An object
could add a call to a trace function by changing the messaging
routine, or could install a messaging routine that would load a new
object table from disk into a new object associative array and then
start executing from the context of that object table.  And other
silly things that seemed fun at the time.

Now I am going into details again...so I'll leave that to another post.

me> And [["$a $b baz"] `ypmatch foo bar`] would do what you'd expect too.
tc> You mean this:
tc>   &{&{$a}($b,baz)}(`ypmatch foo bar`);

Here's a breakdown of what I intended to mean (with $a='tom',
$b='larry';) comments start with #:

	[["$a $b baz"] `ypmatch foo bar`];
		# expand the double quotes
==>	[['tom larry baz'] `ypmatch foo bar`];
		# run the back tick to generate a string
	[['tom larry baz'] 'yuck:0:0:super slug:/bin/slime'];
		# show how the inner squares are dealt with		
	[&moop('tom larry baz') 'yuck:0:0:super slug:/bin/slime'];
		# execute the inner squares and get result string
	['match "larry|baz"' 'yuck:0:0:super slug:/bin/slime'];
		# finish checking for a singly quoted string
	['match "larry|baz" yuck:0:0:super slug:/bin/slime'];
		# show how the outside squares are dealt with
	&moop('match "larry|baz" yuck:0:0:super slug:/bin/slime');
		# execute the outer squares and finally return a string
	'false';

me> it's syntactic sugar that makes perl look more like smalltalk.  
tc> People often want Perl to look more like other languages than Perl. :-)

The reason I say this is because I want it to be obvious that the
contents of the square braces are to be taken as a window onto
something outside of perl.  Something simpler might be where someone
implements their [] set to simply call a korn shell (a forced
example obviously, since this is easily done in perl):

	print ['for i in `ypcat ypservers`; do echo $i; done'];
==>	print &moop('for i in `ypcat ypservers`; do echo $i; done');
	print 'foo.cs.edu bar.cs.edu baz.cs.edu moo.cs.edu';

or if someone wrote an interface to snmp routines:
   print ['snmp_walk public myroot.enterprise.cisco.arp-cache foo.cs.edu'];

or if someone wrote an interface to their favorite sql server:
   @match=split(/:/, ["select (*) where $foo sounds like $bar in $table"]);

of if someone wrote an interface to curses:
   ['wmvaddstr' ["newwin $height $width named banner"] " $x $y $title"];

me> I would like to see tcl used as a front-end to the suggested '[]'
me> syntax.  The reason is that tcl is a very reasonable, small, embedded
me> command language, which could be easily put in any C program.  There
me> are already tcl/sybase/curses/xwindows/motif/oracle/snmp/...
me> combinations out there.  If these tools were all talking to each other
me> with the tcl-send command I could stop worrying about which toolchest
me> to use when tackling something, since they would already work
me> together.

tc> I'm don't see what using tcl instead of a Perl version of these
tc> things would buy you.  

Imagine the scenario where you have a small embeddable command
language such as TCL (tool command language) or SIOD (scheme in one
defun) and a larger far more powerful programming tool, PERL.

(1) First consider the result of adding this command interpreter to perl
just for the purpose of implementing an object-oriented messaging and
inheritance system.  To perl you add &moop() to properly call the 
the embedded command language, and to the embedded command language
you add a new built-in that can call a perl-eval with an arbitrary
string.  Then you write your simple object-oriented system either in
a few low-level C additions to the embedded command language or in
the command language itself.

In particular TCL has support in TK, the x-windows based tcl for a
simple object-construction system to build window-widgets.  SIOD,
which is a tiny version of scheme can support closures and is capable
of running a small object-system written in scheme (although I don't
like the idea of having garbage collection running for a simple
backend.)

This is good because you haven't really gone and added to perl yet you
have an object-oriented perl whose object system is flexible and small
but very general.  Their is little to worry about for forward
compatibility, eg. issues of associative arrays being bigger or
packages holding more complicated state.  Nothing to slow your
favorite old perl down if your not using the object system.

(2) Secondly.  And this is the part that actually interests me...
(mostly as an enigma) Now, imagine that someone has also added an
embedded command interpreter to another of your favorite tools, say a
library of snmp routines, as well as to your favorite sql-capable
database.  And furthermore, your command-interpreter has a `send
command' that allows one command-interpreter to ask another
command-interpreter to execute an arbitrary command.

Now you can write a perl script that sits around checking the load
on another machine, and when that machine starts getting overloaded
your perl script asks the snmp routines what is going on with all
your routers then formats the information and dumps it to the sql
database:

	#!/bin/perl
	INIT: ...
	print 'Just another perl-base sys-admin.';
	while(1) {
	  &dump_routes(`ypmatch routers netgroup`) 
	    if &rup('danger-mouse') > 10;
	  print '.';
       	  sleep(60 * 60 * 60);
	}
	sub dump_routes() {
   	  local($router);
	  while($router = shift @_) {
	    print TMP_FIFO ["send snmp local snmpget ...arp-cache $router"];
	    ...
	    ["send sql local $parsed_arp_cache"];
	  }
	  1;
	}

If you've got the object system running however this might look more like:

	#!/bin/perl
	INIT: ... [inherit sqldb from postgres, sqlcmds] [new sql sqldb]
	print 'Just another perl-base sys-admin.';
	while(1) {
	  [sql.store local ['snmp.routes {' `ypmatch routers netgroup` '}']]
	    if ['info.rup danger-mouse > 10'];
	  print '.';
       	  sleep(60 * 60 * 60);
	}

and suppose that the snmp package is actually another perl script you
wrote for talking to "snmp/udp"  :)

This is good because you can build tools that are more and more
reusable, each with a well defined interface.  And you're not limited
to perl per say, because someone else working down the hall can
implement his database system in C using Postgres, and another person
can write a network object manager in C++.  And what's even better is
that you can do all your report generating and queries in Perl since
your tool is independent of theirs.  Also the object manager can talk
to the database with the same freedom.  With something like tcl you
could also have a graphic front-end to this conglomeration of tools
that the user can reconfigure with tcl commands, so that if they want
to change menu ordering or which tables go in which part of the window
its all very easy.

me> -Someone's already written a dld based dynamic object loader in tcl.
me> -There are versions of tcl that already dynamically load missing
me> symbols.

tc> And someone -- Kevin Stock in 9210080916.AA19163@isfrance.encore.fr> --
tc> last week posted an way to dynamic load C functions from perl.

Yes, but I think that one used dynaload, the tcl one use dld from gnu.
But that's not the point that I hoped to make, which is that someone
wrote a dynamic loader tool for one or the other (tcl or perl)
already.  It shouldn't be necessary to rewrite another.  (this is a
bad example because dynamic loading is not so straight-forward a
matter --eg. it is probably necessary for the process who will use the
library to actually load it.)

me> -Someone's already written a sybased tcl.
tc> And a sybased (etc.) perl.

Yes, the list of things I mentioned was meant to be a list of things
that I think have been already in both perl and tcl (I'm not sure
about a few.)  If these could be integrated it would save the trouble
of having the two communities of tcl users and perl users each hack-up
up their nice tools (syb_perl, and syb_tcl) and it would save 
much duplication efforts.

If there were a version of sybase that talked tcl and supported a
send command all versions of perl (not syb_perl) and tcl (not syb_tcl)
could use the database.

me> -Tcl could implement struct for perl.

tc> Struct is an interesting problem, and I'm certainly not entirely
tc> satisfied with the c2ph approach, but I don't see why that requires
tc> a hybrid language, which is what I hear you asking for.

Well, I'm really advocating a simple but flexible form of intra-tool
communication, based on the merging of two good tools in a manner that
is suitable for their original design intention.  A clear and simple
emulation of structs might be an added benefit.

me> -We could get rid of some of the features already in perl.
tc> I don't think you'll make a lot of friends by removing features,
tc> since most have their champions.  Did you have any candidates for 
tc> deletion?

I don't really desire deleting anything from perl, the idea behind
that statement is to make you think ``Gee, if I were going to delete
something from perl what would it be?''  Then to think ``What do these
two things have in common, and how can I factor this out so that they
can share it, and better yet, some else could use it too.''

/charles
PS.  "wafe" is great idea.
PPS.  Just another perl hacker (Here's the key to using assoc. arrays for 
object systems):

# Takes a string and returns a reference to the variables of that
# name.  Used primary to access an associative array by string.
# Eg. local(*tab) = name2table("assoc_array"); $tab{'foo'}='bar';

sub name2table {
    local($name)=$_[0];
    eval("*$name");
}