[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Compiling.




In a previous article Jean-Michel Hufflen points out some problems he has
run into compiling some module in lelisp.  Vincent Prunet responded to this
message but i'd like to add my two cents.

=>    Let us consider the following button specification:
=> 	({butobj}:create  ....
=> 	           (lambda (button)
=> 	               (:display_help_menu ({link}:find button 'ctedit))))
=>    It is not equivalent to:
=> 	({butobj}:create ....
=>                  #'(lambda (button)
=> 	                 (:display_help_menu ({link}:find button 'ctedit))))
=>    which signals an error.

As Vincent pointed out, the #' macro is a shorthand for calling the LeLisp 
function "function", which basically ends up *quoting* your lambda expression.  
However, you say the second signals an error but you don't say where or what
error.  i imagine that it is not an error at compile time.  
Complice will happily compile your file.  However you can have a runtime error
if you've never bothered to export a function that you wish to use.

The difference is what the actions associated to the buttons are, after
complicing.  In the first case the action is a symbol, e.g., 
#:<enclosing function name>:g106, which is the generated, and compiled, function. 
It is important to note that when this function is compiled, the function 
:display_help_menu must be present in the complice environment (for example its 
definition is in the collection of files that make up the module or in some 
imported module).  The action in the second case is the quoted lambda expression 
which is executed, at runtime, using the button as the argument.  In this case 
the :display_help_menu must be present in the runtime environment.  That is, it 
must be exported in its defining module.  

=>    Second problem.  If you define a menu as a variable:
=> 	(defvar :tools_menu
=> 	  (let ((button_1 ...) ... (button_n ...))
=> 	    ({pulldown}:create 0 0 'column "My-tools" button_1 ... button_n)))
=> an error message concerning the display is put down.  The right solution
=> seems to be:
=> 	(de :tools_menu ()
=> 	  (let ((button_1 ...) ... (button_n ...))
=> 	    ({pulldown}:create 0 0 'column "My-tools" button_1 ... button_n)))

Yes, it is true that it is hard to compile code that wants to execute in-line,
which is what a defvar, a setq, or having a function call at the toplevel of 
a lelisp file will do.  When it is read into the complice environment the code
is executed.  Then and there.

The problem with the above comes from the fact that creating these objects
calculate the size of the object (width, height, etc).  In the case of buttons
this means getting the size of the label.  The size of the label depends often
on the font (and the current Lelisp display (e.g., X11) you are using).  Thus
Lelisp functions such as width-substring or width-space try to find the current
display, which has not been opened in the compile-time environment.  Vincent
has already explained about the initializemodule routine.

=> These two problems are surprising since they concern features that work fine
=> in interpreted mode.  Moreover, the second problem forces us to rewrite all 
=> the uses of each menu!

The first problem is one of visibility of functions, in fact you can have the
inverse problem by loading something in interpreted mode that is typically 
compiled and all of a sudden "breaking" a function that use to work by 
inadvertently redefining it.  The action of a button *must* be a lambda or a 
symbol that is taken to be a function name, which takes the button as argument.
One then only has to assure that the function is visible at runtime.  

Compiling the code is difficult but a worthwhile exercise.  
Feel free to ask early on questions about compiling stuff, in particular.
the display error is a common when people are first trying to integrate and
compile code.  Thus, you can profit from our previous suffering :-)


	--janet