Experimental "peer to peer" modular programming concept
- Posted by ryanj May 06, 2015
- 1976 views
Working on large GUI applications over the years, i have always been frustrated with how difficult it can be to organize all the parts of an application, especially since there is usually special data processing mixed with user interface code and various states or views the application may switch to. Usually, i end up with a small main file and 2 or 3 huge files, with GUI and data processing code mixed together, and a few lower-level libraries that perform specific generic functions. It is difficult to define clear "modules" or some sort of hierarchy when different parts of the program need to communicate with other parts, so i end up with a make-shift message queue system that is difficult to maintain across different parts of 2 or 3 large files. Part of the problem is the way include files work assumes that an included file is somehow lower in the hierarchy, and there is no clear way to make different parts of the program "peers" or independent "modules" without some other library to include them and control them.
Does anyone else have this problem?
Possible solution: I have created an experimental "sync.e" library that allows any include file in a program to send messages without being aware of where they get received. Each file has to include "sync.e and subscribe to a "sync group", specifying a routine_id that will process sync messages. If any subscriber of the group calls sync:send(), all other subscribers' handler routines will be called by the sync.e library. Each library can then process incoming messages without a queue or tasks required.
No processing queue or controlling hierarchy is required. A main file can include many small .e files and not have to do anything with them once everything is initialized. Each .e file can be independent of the others, handling it's little part of the whole program. For example, if i create a file browser application, separate .e files could handle their own parts of a GUI: a folder tree, a location bar, a file list, etc. If any part of the gui is changed by the user, a message is sent out, and the other files process what they need to and update their part of the gui. Another file that is responsible for manipulating files could receive a message to do something with a specified file (open, delete, copy, move, rename, etc.) This makes the program very modular and easier to add or remove features later.
This is still experimental and theoretical, but i am currently rewriting all the source code of RedyCode to test this concept.
Here's the experimental sync.e library. Any thoughts? Let's discuss.
sequence gNames = {}, gSubscriberNames = {}, gSubscriberRids = {} atom debugRid = 0 public procedure send(sequence groupname, sequence subscribername, sequence msgname, object msgdata) --sync data with other subscribers in group atom idx = find(groupname, gNames) if idx > 0 then for s = 1 to length(gSubscriberNames[idx]) do if not equal(gSubscriberNames[idx][s], subscribername) then if gSubscriberRids[idx][s] > 0 then call_proc(gSubscriberRids[idx][s], {groupname, subscribername, msgname, msgdata}) end if end if end for end if if debugRid > 0 then call_proc(debugRid, {groupname, subscribername, msgname, msgdata}) end if end procedure public procedure subscribe(sequence groupname, sequence subscribername, atom msghandlerid) --subscribe to a sync group to receive sync updates atom idx = find(groupname, gNames) if idx > 0 then gSubscriberNames[idx] &= {subscribername} gSubscriberRids[idx] &= {msghandlerid} else gNames &= {groupname} gSubscriberNames &= {{subscribername}} gSubscriberRids &= {{msghandlerid}} end if end procedure public procedure unsubscribe(sequence groupname, sequence subscribername) --unsubscribe from a sync group atom idx = find(groupname, gNames) if idx > 0 then gNames = remove(gNames, idx) gSubscriberNames = remove(gSubscriberNames, idx) gSubscriberRids = remove(gSubscriberRids, idx) end if end procedure public function list_groups() --list all sync groups return gNames end function public function list_subscribers(sequence groupname) --list all subscribers in a specified sync group atom idx = find(groupname, gNames) if idx > 0 then return gSubscriberNames[idx] else return 0 end if end function public procedure debug(atom debughandlerid) --register a routine to be called for debug messages debugRid = debughandlerid end procedure