Skip to content
kirv edited this page Oct 17, 2010 · 56 revisions

Welcome to the thinobject wiki!

thinobject—introduction

thinobject is an approach to organizing and associating data and executables on a computer system. Executables are contained in a class directory under a thinobject library, e.g., /usr/local/lib/tob. They are executed in the context of an object, which is a directory containing a symlink to a class directory. That is, the system cds into the object directory and then runs the executable.

There are no restrictions on what exectuables (or methods) must do, how they are written, or in what language. For convenience, some environment variables are exported and may be used by methods, or they can be ignored. Normal system utilities, e.g., ls, cat, find, and so on can function as thinobject methods, and so are included in the Directory class which forms the root of the class hierarchy.

A special program, the executive or enabler tob, is the engine that makes the system work. tob is invoked with an argument of the form “object.method” and then works to resolve or identify the object—a directory—and cds into it. Next, tob follows the class link, a symlink named “^” or “.^”, to establish a search path by which it will try to resolve the given method. The class itself can include a class link to a parent class, so if a method isn’t found immediately it may be found further along the search path. Once a method has been resolved, it is invoked using exec.

Perhaps the tob executive or enabler might be best viewed as a shell, since it is taking a command, parsing it, identifying an exectable to run, then invoking that executable using exec. The tob program can be run explicitly, or perhaps can be invoked automatically if the system shell provides a command-not-found hook.

A thinobject application class can do whatever it needs to do in an object directory. The methods of an application probably will want to agree on what’s there, but they might create and manipulate any sort of files or directories, perhaps other objects, etc.

A simple example application might be created as follows, given appropriate permissions, and assuming a Unix shell environment:

    $ TOB=/usr/local/lib/tob
    $ mkdir -p $TOB/Misc/HelloApp
    $ printf "%s\n" "#\!/bin/sh" "echo hello there \$USER" > $TOB/Misc/HelloApp/hi
    $ chmod +x $TOB/Misc/HelloApp/hi

An object can be created of that type:

    $ mkdir say
    $ ln -s $TOB/Misc/HelloApp say/^

and the method invoked:

    $ tob say.hi
    hello there ken

thinobject—core executables and classes

thinobject aims to implement object-oriented systems on the filesystem, using ordinary files, directories, and executables.

It’s really pretty simple, even obvious: an object (a directory) contains a link to a class (another directory) which contains methods (ordinary executables). If a method is invoked on an object, the thinobject system (the tob enabler) searches for an executable of that name in the object’s class, cd’s into the object, and runs the method.

Everything pretty much falls out from this simple search convention, and the result is a fully buzzword-capable object oriented system that can support applications.

tob—the enabler

The tob program parses commands in the form OBJECT.METHOD ARGUMENTS, but does nothing with arguments but pass them along to the called method, so it really boils down to parsing OBJECT.METHOD. The method part follows a literal ‘dot’ character and so can be trivially stripped off—which leaves just OBJECT to worry about. (Note that this implies that method names cannot contain ‘dots’.)

So the main work of tob is to resolve the object, and thinobject defines a few conventions for this, extending beyond the obvious case where object is immediately found as is. These include (informally):

  • an object can be found a through symlink (duh)
  • a hidden object .foo can be resolved from object name foo
  • a hidden object can be resolved ‘behind’ a symlink—even if the target doesn’t exist

the class link—^

thinobject gives one character a special meaning, if it is used as the name of a symlink: ^ (or .^ to be ‘hidden’) is assumed to point to a class directory. The existence of ^ in a directory makes that directory a thinobject. In fact, if both foo and .foo exist, and .foo/^ exists but not foo/^, then object foo will resolve to .foo. (This is an additional convention to those listed above.)

tob requires that class links point to a sanctioned location, though, so not just any directory-containing-executables can be linked. This is intended to be analogous to the restriction that shell executables are only found by searching the shell’s PATH variable. It is assumed that the directories listed in PATH—or here, in TOB_LIBRARY—are under some sort of protection, so cannot be easily violated by sneaking in bad apples to the mix.

core classes

Directory

The thinobject semantics can work even if no ^ is provided, so the root class is Directory. Most of the executables in Directory are just symlinks to ordinary programs in /bin/ et al, like cat, grep, find, and so on.

Object

The Object class includes some methods more specific to the thinobject conventions than those applicable to any directory, but it does include a symlink to the Directory class, so all those methods are available as well. If a thinobject is created with the tob-new program, the Object class will be assumed if none is given.

not-so-core classes

Aggregate

The Aggregate class passes methods called on it to its contained objects. Given:

    $ tob-new things Aggregate
    $ tob-new things.foo SomeClass
    $ tob-new things.bar SomeOtherClass

then:

    $ tob things.action

should be equivalent to:

    $ tob things.foo.action
    $ tob things.bar.action

The order should be controllable, some contained objects might be excluded, etc.

TimeSeries

The TimeSeries class is included with the core since it’s a workhorse in the applications so far explored. It’s a work in progress and much remains to be done, but the aim is to provide a way to store timestamped data, text, files, images, thinobjects, anything. An application might choose to subclass TimeSeries, or it could create individual TimeSeries objects for things like logs, captured events, etc..

File

The File class is currently a stub, there mostly because the thinobject semantics seem to make it seem reasonable to have. It doesn’t actually do anything yet, but maybe can be used down the line. Whether a file ‘object’ might be resolved from a tob object.method invocation or by other means, if no directory (or other target) is found and a file exists, why not treat it as an object? For now this is a placeholder, and it’s too early to get in and specify much more about it.

Array

This is not even a stub, just an idea that seems to extend from the Aggregate description above. Array would work in a similar way, but would contain only objects of the same type, whereas Aggregate objects can be of any type. No code exists for this. This could be an example of an alternate way to associate a class with an object, since the ^ might not be required in each contained object…

syntax

Running thinobject applications from the shell involves using the tob enabler program. The simplest form would be

    $ tob object.method

where object may be a pathname including directories, etc. An alternate form is provided, e.g., to work with multiple objects:

    $ tob --method method object ...

Objects can also be contained in other objects, and tob interprets the dot delimiter . as separating objects. The dot separator will work whether classlink ^ is present or not—but if it’s present, the class pointed to must be under TOB_LIBRARY or the operation will fail (unless --not-strict is specified).

The tob resolver tries fairly hard to resolve an object, and object or other names in the object specifier may include dots.

Classes can overload method names of parent classes, and the super meta object can be used to cause method search to keep looking beyond the first match of a method. E.g., a.b.c.super.foo would not call the first foo found but the second on the c object. On the other hand, the resolver would first check for an object named ‘super’, and would have invoked the foo method on it if found.

Once an object is resolved, tob cd’s into the object directory, then invokes the method.

methods

Methods are executable programs found in a class directory. Methods are run in the object directory, so anything, e.g., files, other objects, that are included in the object are immediately or locally accessible. The thinobject system makes no restrictions on what can or cannot be in an object (with the sole exception of the ^ or .^ class link), so an application can do whatever it needs to do.

Methods are ordinary executable programs, so can be written in any language.

environment variables

The tob enabler sets a number of environment variables. Here’s an example:

$  tob-new ob
$  tob ob.show-envars
TOB_attribute_search_paths='.:./^:./^/^'
TOB_caller_path=/home/site/GOES
TOB_caller_path_to_object=./ob
TOB_class_path='./^'
TOB_method=show-envars
TOB_method_search_paths='./^:./^/^'
TOB_object=ob
TOB_type=Object:Directory
TOB_resolve_method_path()

attributes

thinobject has no formal or fixed meaning of attributes, but generally they’re probably whatever stuff might be found in an object. An application could choose to make its own conventions.

An attribute search path is, however, defined by tob, starting at the object directory itself (./, since we’re already there) and continuing down (up?) the method search path. But tob now allows an object to link to a non-class directory—i.e., another object—and those links would precede the method search path. I have not yet put this to use, but I think it will be of great use in sharing attributes as opposed to executables in applications—e.g., maybe for javascript or stylesheet includes in a web application.

extended conventions

The Object._default method, invoked if the method doesn’t resolve, defines special meaning to file names beginning with ‘@’ or ‘%’. A search is made for ‘@method’, then ‘%method’, and if found, then Object._default-list or Object._default-dictionary is invoked on the matching file. Thus, ‘@foo’ can be interpreted as a list attribute, ‘%foo’ as a dictionary attribute (or maybe object types File/List and File/Dictionary…).

The TimeSeries object makes use of this convention, storing its data in files beginning with @ since they represent ordered lists.

An attribute form that has been found useful is to name files explicitly with the tag and value, i.e., ‘TAG=VALUE’. This can be used for settings in the object, perhaps for flags (e.g., do something if ‘foo=bar’ exists), or even for containing settings (‘interval=3600s’).

The file ‘%’ has found use for containing settings in tag=value pairings, i.e., like a config, rc, or ini file. A further convention is that such a file should perhaps not be written automatically, but rather left for configuration settings by the user.

But really, none of these conventions are really nailed down in the core thinobject scheme.

installation

Thanks to git for providing a great and sensible way to organize all this, and to github for hosting it! The current repository includes an install script under the bin/ directory. It uses rsync, so should manage to copy/install only changed or newer elements if an installation already exists, and also should be able to create the target directories on the fly. It operates locally by default, or can be called with the—host option to move stuff to another machine.

dependencies

Efforts have been made to try to use features available in base Linux installs, so tob should work without requiring additional software to be installed. (The perl code in TimeSeries may need some additional modules, however, for handling time conversions, file locking, etc., so the ideal is not yet really achieved.)

thinobject version 2

I’m calling this, roughly, version 2, as it’s about the third go-round for the overall scheme, with the 0th one being very crude and misguided, the 1st one being a bit cleaner and more focused, but still with a bunch of screwy ideas, and now the 2nd one having been guided by sage advice from my primary unpaid consultant. The syntax and embedded decisions are simpler and more consistent than previous versions, and I feel that the system should now be capable of robustly supporting real work.

unit tests

A suite a short test scripts is included under t/, and can be invoked as $ t/run-all-tests. (A bug is that it does so against the installed system, not the code in the repository.) The tests should exercise several conditions and situations to be handled by tob-new and tob, and have already proven useful in fleshing out and fixing issues.

thinobject is intended to be open source

The GNU GPL3 license should apply, but we’ve only barely managed to try to dot some of those t’s. The tob and tob-new programs include the recommended text, but surely every method doesn’t need that—does it? A bit hazy on the details…

remaining work

A lot of work remains in several directions to make this thing realize its potential. Some topics:

make the shell automatically call tob

This is very doable under bash v4 using the file-not-found handler. I wish bash 4 was already ubiquitous, but it isn’t, in my experience, so for now I’m still stuck typing tob all the time. The trick is a no-brainer: the object.method syntax is unlike the look of most executables, so will likely not be found by the shell. The file-not-found handler invokes tob on the given command, and away we go: native objects (sort of) in the shell.

do something with the File class

This is perhaps creaping feeturitus, but it just seems cool… I suspect that the current handling of list and dictionary attributes could be realized by defining classes like File/List and File/Dictionary. One thing that makes me not dive right in is the whole mess that can result from coupling file naming conventions with behavior, but maybe those concerns are misplaced. In fact we’re already doing that, e.g., automatically invoking Object._default-dictionary if the given method can be resolved by attaching the % prefix.

performance

tob is currently a bash script, about 500 lines long, but it’s mostly doing simple things. Maybe the system could be faster if it were implemented in C, or maybe Python? I don’t know, and my problem domain seems willing/able to accept crappy performance, so this is not a huge priority at the moment. I figure the system will automatically be 10 times faster in 10 years, anyway.

But really, thinobject is probably mostly a launching engine, and the performance needs might well be handled in the methods defined for any given class. While most of my methods are written in sh, bash, awk, perl, or python, they can be written in other languages as well. Also, once invoked, a method can do arbitrary things, and its code could be optimized and worried over, etc., to meet whatever goals apply.

The thinobject semantics might be supported by special tools provided to be used with other languages. I do have an old ThinObject.pm perl module which does this, making the same decisions in its code that tob does in bash source. My sage consultant has described a possible scheme where python classes could be written to replace some key, e.g., bottleneck, methods with some higher performance versions, but leaving much of the existing code set in place as ‘good enough’.

other class-linking schemes

Instead of the ^ symlinks, some kind of extended attribute might be used to associate an object (file or directory) with a class. I’d like to think that it could still be thinobject if that were done, but maybe could fit into other schemes more easily. For one thing, maybe those attributes would ‘follow’ and stay attached to whatever they’re associated with more easily, more robustly.

bash hash

Bash doesn’t actually search the PATH variable every time an executable is invoked, but perhaps does it once and then stores what it found in some kind of hash structure. That hash can, I think, be preset with some other set of executables, and this would seem to work nicely into the thinobject scheme for method search.

non-class-based functions

I’m not sure about this, but some folks have issues with ‘object-oriented’ anything, and so will likely discount the thinobject scheme offhand. I don’t think it necessarily has to be strictly class-based, however, though I have no semantics to offer for how other schemes might work.

Probably not the same thing, but there’s a sort of syntactical opening provided in that currently ^ is used for the classlinks, but using ^ as a prefix is not defined. It may work out that classes—or maybe objects—could include named links that are somehow searched in or to the side of the normal class-based search path. If a particular object instance needs to be able to phone home, maybe a link could be dropped into it, like ^phoner -> /usr/bin/phoneapp… Is that was ‘mixins’ are? I have no idea…

type checking

This has been explored a bit, and I think holds some promise of actually being useful. A method would—somehow—define a prototype for its argument list so that a call to it could—somehow—be checked. Maybe the method itself could choose to do this, maybe by invoking another method for the purpose, or maybe the system could—somehow—do the checking before calling the function. Complications include the fact that methods are arbitrary, so no assumptions can be made about them; methods can do whatever they please in processing their arguments, and options or arcana such might confuse an external checker. Whatever. It might work.

One approach might be to have an entry for each method of a class in a file, .e.g., %prototype, identifying the options and argument types, and providing sufficient information to parse and check the argument list. This wouldn’t necessarily be trivial to do, but could be done in a separate method. (Object.scan-arguments is a first attempt at something along those lines.)

the future

thinobject is currently in the first they ignore you phase of invention or development, and I don’t have any idea if it will advance to the (shudder) then they ridicule you stage, let alone the (as if) then you win phase. But it all seems like a no-brainer to me (which could have an unfortunate reverse meaning…), and it seems to work. That is, pretty much solely from the search-path semantics all the OO buzzwords seem to be covered.

The inception of the whole idea was, in part, that I knew and understood flat files, but I didn’t really ever grasp databases. I had to store information, and I needed to operate on that stored stuff. thinobject provides a simple framework—or exposes one already existing in the filesystem—to associate specific operations with selected data.

warning… this seems to be digressing to a diatribe

My feeling is that, as disks get bigger and processors get faster, there’s going to be less need for ‘special’ optimizations for storing and operating on data. Hence, a future system might aim to keep things simple, and let the system work out the performance worries and optimizations. In other words, I predict that whole operating systems might someday be implemented in this scheme or something like it.

Consider the current situation. We’ve got available executables stored in /bin/, /usr/bin/, etc.—all essentially in one big pool. Any executable can be invoked anywhere in the system, on any target object, whether or not that makes any sense. In contrast, thinobject says: ‘here are the executables that are available to operate on these data’.

Ok, enough of that, and sorry for the digression and grandiosity…