Libraries
GavinWraith (26) 1563 posts |
Are !SharedLibs and the SharedULib module part of the RISC OS distribution? If not, should they be? |
Stephan Kleinert (2271) 70 posts |
+1 from me; as this would make installing applications which were built with gcc and rely on !SharedLibs much easier. |
GavinWraith (26) 1563 posts |
Libraries are supposed to be containers for reusable code. The word module tends to be used in the same sense. It took a little time for this concept to mature in Lua, as is explained in chapter 17, Modules and Packages , in edition 4 of Programming in Lua . There used to be a built in function, module, which no longer exists. Anyway, I was pretty muddled about it, and that rather shows in the ad hoc ways that I defined Lua libraries in the past. Now I think I understand better. A module should be a file that returns a table. The indices of the table are the names of the values defined in the module. Modules should be loaded using the function require: . The variable x now has the value of the returned table; it is only a convention to write . The require function takes as argument the file name of the module; it searches for it in the places defined by the template string in the system variable LUA_PATH (or LUA_CPATH in the case of dynamically linkable modules written in C), filling in the ? in the template with its argument.
You could mimic some of the functionality of require in earlier versions of Lua using the function dofile (now obsolete). With dofile the emphasis was not so much on the returned value. You could simply execute the code in the file – if it contained no return statement then the value nil was returned. The present approach, to which I have been won over, is a bit more careful with scopes and error-handling. |
GavinWraith (26) 1563 posts |
I am building up to attempting a complete rewrite of the RiscLua wimp libraries. I do not think that I tackled error-handling properly in my earlier efforts. Every sys call to Wimp_Poll yields control to the task-manager, and one’s program has no control over what happens next. Its only responsibility is to give sensible arguments to the call. All SWIs used by RiscLua are error-returning, though this does not guarantee that they will actually return. If the sys call returns with an error then one’s task must call its error-handler (which by default should issue an alert message to a separate wimp-task; I use Reporter) and call Wimp_CloseDown. If the sys call returns a reason code, one’s task will look up a handler for it and call the handler. In my previous efforts handlers only returned a non-nil value if they wanted the task to quit. I now think that the quit-signal should not be returned by the handler. Instead the handler should set a quit attribute in the wimp-task and the value returned by the handler should be an error-signal, with nil the signal for no error. This is a bit like the C convention. Handlers need to tell their task two things: was there an error? and should you quit? . In my previous schemes I only addressed the latter signal. Handlers have two methods available for returning information: as a returned value, or by setting an attribute in the task. The latter method is slightly dodgy for error-handling because error-conditions must be cleared if infinite loops are to be avoided, whereas returned values go out of scope almost immediately. There is also the security angle: all handlers have the wimp-task itself in scope within their bodies, and so all its attributes too. On the other hand, returning the quit-signal as well means that some functions need an extra parameter to propagate it. These are my arguments for a new approach. If anybody can point out something that I may have overlooked, I will be grateful for feedback. It is the handlers that determine a wimp-task, of course, and every action of which they are composed may raise an error. I was not addressing this previously as formally as I should have done. Another point is that Lua now allows errors to be of any type, not just strings, and this facility might be useful. |
Stephan Kleinert (2271) 70 posts |
Coming from a C/ObjC background, the idea sounds good to me. But since I haven’t done much with the Wimp libraries (other than !Mitosis, which uses more toolbox than Wimp), I can’t really comment much on this. |
Rick Murray (539) 13840 posts |
Yes. It should not be the duty of your library to be telling the programmer whether or not the application should quit1. In some cases, such as a call to load a window from a template failing, there’s not much else the program can do, but it should be up to the programmer. With that in mind, there’s only one thing that a function needs to say – was there an error? DeskLib handles this quite elegantly. Many functions return a pointer to an error block, and if there was no error, this pointer is set to NULL (MOV R0, #0). This means you can either do something like: errblk = SomeFunction(Blah, Blah); ...do something with errblk...; or, if you don’t care what the error was, only that it happened: if ( SomeFunction(blah, blah) != NULL ) OhCrapCode(); I don’t know how Lua does stuff. Would a NULL-or-errorblock approach work? 1 Certainly, it would be useful if an application could stay alive long enough to dump potentially unsaved user data into Wimp$Scrap so that a failure to press F3 once in a while doesn’t mean an hour of work is lost. That’s one of the things that really bugs me with NetSurf – when it crashes it will throw this ridiculously over-detailed log at me, but it makes no attempt to preserve the text in a writeable area in the current foreground window – something the user may have been writing over some measure of time… |
GavinWraith (26) 1563 posts |
Sorry, my imprecise words may have given a wrong impression. What I have is an error method with two arguments, the first an error message and an optional second argument which if non-nil sets the task’s quit attribute. If the argument is omitted then that is the same, by Lua Fu, as being nil. The user can override the error method with her own, like in BASIC. So if the wimp-task is called
I hope this answers you ok. I have my new task library working now. The following program creates a task called
OK, not very transparent. preclosedown is a method which, if it exists, is run after polling stops. alerts is a list of the task-handles of alert-windows that the task has fired up, remove is a function in the table library which pops the last item off a list and returns it. kill should be self-explanatory. _ENV is a local variable defining a chunk’s environment. So setting it to eph means that all variables from there on which have not been declared as local are taken from the table eph. So for example the next line is equivalent to . This sets the null-reason-code handler to eph.QUIT which just does eph.quit=true . If you are unfamiliar with Lua’s syntax, the dot (.) gives you an object’s attribute and the colon (:) calls an object’s method with its first argument set to the object itself.
|