Difference between revisions of "Scheme"
(Intro: References) |
(Move guile-hackers.txt') |
||
Line 2: | Line 2: | ||
[https://wingolog.org/archives/2013/01/07/an-opinionated-guide-to-scheme-implementations An opinionated guide to scheme implementations] is a nice overview of dialects. | [https://wingolog.org/archives/2013/01/07/an-opinionated-guide-to-scheme-implementations An opinionated guide to scheme implementations] is a nice overview of dialects. | ||
+ | |||
+ | === Ancient Notes === | ||
+ | The following was written in 2000 when Guile was first added to GnuCash. It's a bit out of date (though the CMU Scheme Repository URI was updated at the time it was moved to the wiki) but might prove interesting. | ||
+ | |||
+ | |||
+ | This file is intended to contain information for those interested in | ||
+ | working on the guile bits of GnuCash. | ||
+ | |||
+ | I've recently added some GUI functions callable from scheme. This is | ||
+ | generally pretty straightforward, and you can look in the code to see | ||
+ | how I did it, but there are a few bits you have to be careful about. | ||
+ | |||
+ | One of the main sources of useful information is "info guile-ref". | ||
+ | This contains the documentation for all the guile C-side functions | ||
+ | like <tt>SCM_CAR()</tt>, <tt>scm_append()</tt>, etc. that manipulate opaque SCM objects | ||
+ | from the guile side. | ||
+ | |||
+ | Given that and a reasonable understanding of GTK/GNOME, you should be | ||
+ | able to follow what I've done. | ||
+ | |||
+ | ==== Introduction To Scheme and guile ==== | ||
+ | |||
+ | Please skip this if you already know what Scheme is and why it's | ||
+ | so cool . . . | ||
+ | |||
+ | Scheme is a dialect of LISP (List Programming), one of the earliest | ||
+ | programming languages. It makes so many things easy it's just not | ||
+ | funny. It can be a little confusing for people raised on C and Java, | ||
+ | but any time taken to learn it is made up for with easier-to-write, | ||
+ | easier-to-debug, more reusable, and more robust code. | ||
+ | |||
+ | Guile is an implementation of standard Scheme which is easily | ||
+ | embeddable in C, making multi-language development relatively | ||
+ | straightforward. You can easily access data and procedures from | ||
+ | either end. Guile supports a superset of R4RS (the Scheme standard). | ||
+ | For initial experimentation, you can use Guile as an interactive Scheme | ||
+ | shell to play around with the system. | ||
+ | |||
+ | FIXME: Starting gnucash as a guile shell. .. | ||
+ | |||
+ | While the Guile documentation (in info format) explains | ||
+ | Guile specifics, it doesn't have much information about Scheme, | ||
+ | the language. The | ||
+ | [https://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/0.html Internet Scheme Repository.] | ||
+ | |||
+ | has quite a useful collection of information, including | ||
+ | FAQs, online copies of the Scheme standard (which is actually | ||
+ | quite readable and useful), and pointers to web tutorials | ||
+ | and other resources. | ||
+ | |||
+ | ==== Garbage collection ==== | ||
+ | |||
+ | One issue to keep in mind is that of garbage collection. You cannot | ||
+ | pass a scheme side item to the C side (through a SCM) and then store | ||
+ | that object off somewhere on the C side such that it lives longer than | ||
+ | all of its guile side references. If you do, you're likely to get a | ||
+ | crash. The problem is that guile's garbage collector only knows to | ||
+ | save guile items that still have guile side pointers, or that are | ||
+ | found somewhere on the current C side stack. If you store a SCM item | ||
+ | off in a C data structure (say a callback pointer), and then return to | ||
+ | the guile side and drop the guile-side reference to the item, guile | ||
+ | may garbage collect it before it's used by the C side. | ||
+ | |||
+ | For example, this psudeo-code is a problem: | ||
+ | <syntaxhighlight> | ||
+ | void gnc_some_function(SCM scm_thunk) { | ||
+ | gnc_set_push_button_callback(some_button, scm_thunk); | ||
+ | } | ||
+ | |||
+ | (define (unsafe-guile-function) | ||
+ | (let ((my-callback (lambda () (display "Hello\n")))) | ||
+ | (gnc:some-function my-callback))) | ||
+ | </syntaxhighlight> | ||
+ | The problem here is that if you call unsafe-guile-function, it | ||
+ | registers the pointer to the anonymous lambda created in the let | ||
+ | construct with the button on the C-side and then returns. As soon as | ||
+ | it returns, guile has no more references to the anonymous lambda, and | ||
+ | it's not on the C stack, so guile thinks it's OK to garbage collect | ||
+ | the function even though the C side has a pointer to it and may still | ||
+ | use it. | ||
+ | |||
+ | The moral of this story is that if you need to have the C side ferret | ||
+ | away a scheme item for later, you must also keep at least one | ||
+ | reference to that item on the guile side until the C side is finished | ||
+ | with it. | ||
+ | |||
+ | You can protect an object using <tt>scm_gc_protect_object</tt>. When you're done | ||
+ | with it you can release it using <tt>scm_gc_unprotect_object</tt>. | ||
+ | |||
+ | ==== Guile Interrupts ==== | ||
+ | |||
+ | Another issue that I'm not quite sure of myself yet is that of | ||
+ | interrupts. Guile has the ability to protect certain segments of code | ||
+ | with <tt>SCM_DEFER_INTS/SCM_ALLOW_INTS</tt>, but at the moment I'm not sure | ||
+ | when this is required. If anyone gets the chance to check this out | ||
+ | before I do, then please edit this file and put your findings here. |
Revision as of 00:08, 26 May 2020
The programming language Scheme is used for reports in GnuCash in the implementation Guile. It is a main dialect of Lisp.
An opinionated guide to scheme implementations is a nice overview of dialects.
Contents
Ancient Notes
The following was written in 2000 when Guile was first added to GnuCash. It's a bit out of date (though the CMU Scheme Repository URI was updated at the time it was moved to the wiki) but might prove interesting.
This file is intended to contain information for those interested in
working on the guile bits of GnuCash.
I've recently added some GUI functions callable from scheme. This is generally pretty straightforward, and you can look in the code to see how I did it, but there are a few bits you have to be careful about.
One of the main sources of useful information is "info guile-ref". This contains the documentation for all the guile C-side functions like SCM_CAR(), scm_append(), etc. that manipulate opaque SCM objects from the guile side.
Given that and a reasonable understanding of GTK/GNOME, you should be able to follow what I've done.
Introduction To Scheme and guile
Please skip this if you already know what Scheme is and why it's so cool . . .
Scheme is a dialect of LISP (List Programming), one of the earliest programming languages. It makes so many things easy it's just not funny. It can be a little confusing for people raised on C and Java, but any time taken to learn it is made up for with easier-to-write, easier-to-debug, more reusable, and more robust code.
Guile is an implementation of standard Scheme which is easily embeddable in C, making multi-language development relatively straightforward. You can easily access data and procedures from either end. Guile supports a superset of R4RS (the Scheme standard). For initial experimentation, you can use Guile as an interactive Scheme shell to play around with the system.
FIXME: Starting gnucash as a guile shell. ..
While the Guile documentation (in info format) explains Guile specifics, it doesn't have much information about Scheme, the language. The Internet Scheme Repository.
has quite a useful collection of information, including FAQs, online copies of the Scheme standard (which is actually quite readable and useful), and pointers to web tutorials and other resources.
Garbage collection
One issue to keep in mind is that of garbage collection. You cannot pass a scheme side item to the C side (through a SCM) and then store that object off somewhere on the C side such that it lives longer than all of its guile side references. If you do, you're likely to get a crash. The problem is that guile's garbage collector only knows to save guile items that still have guile side pointers, or that are found somewhere on the current C side stack. If you store a SCM item off in a C data structure (say a callback pointer), and then return to the guile side and drop the guile-side reference to the item, guile may garbage collect it before it's used by the C side.
For example, this psudeo-code is a problem:
void gnc_some_function(SCM scm_thunk) {
gnc_set_push_button_callback(some_button, scm_thunk);
}
(define (unsafe-guile-function)
(let ((my-callback (lambda () (display "Hello\n"))))
(gnc:some-function my-callback)))
The problem here is that if you call unsafe-guile-function, it registers the pointer to the anonymous lambda created in the let construct with the button on the C-side and then returns. As soon as it returns, guile has no more references to the anonymous lambda, and it's not on the C stack, so guile thinks it's OK to garbage collect the function even though the C side has a pointer to it and may still use it.
The moral of this story is that if you need to have the C side ferret away a scheme item for later, you must also keep at least one reference to that item on the guile side until the C side is finished with it.
You can protect an object using scm_gc_protect_object. When you're done with it you can release it using scm_gc_unprotect_object.
Guile Interrupts
Another issue that I'm not quite sure of myself yet is that of interrupts. Guile has the ability to protect certain segments of code with SCM_DEFER_INTS/SCM_ALLOW_INTS, but at the moment I'm not sure when this is required. If anyone gets the chance to check this out before I do, then please edit this file and put your findings here.