RE: The Guile junk drawer and a C plea (was: [PATCH] Addnondestructive delq1, delv1, and delete1.)

2024-06-29 Thread Maxime Devos

>Regarding the junk, I very much agree. I also look forward to getting rid of 
>ice-9 :). As has been spoken about here previously, I suggest that we design a 
>new module hierarchy, introduce aliases for module bindings, and still supply 
>the old module hierarchy during a few years for backward compatibility.

On this, and on responses on potential harm introduces by incompatible changes:

It’s not like Python where semantics were changed in some changes, this is 
about simply renaming stuff. We can keep the (ice-9 ...) modules/bindings 
forever – if not in Guile, then in a separate Scheme library (so out-of-date 
Scheme libraries can still be used after installing this compatibility library 
with whatever is the local package manager).

The default environment is irrelevant to most Scheme libraries, since it is 
irrelevant to any library defining modules with ‘define-module’, 
‘define-library’ or ‘library’ forms (which is pretty much the only reasonable 
way to define modules unless you are making your own system). This already 
reduces a lot of compatibility concerns. An important exception is anyone doing 
‘eval’ or compiling expressions (think anyone doing the equivalent of “guile -l 
script.scm”.

Now let’s look at ‘eval’ and the like, in particular where it uses the default 
environment.

>From the manual:

Scheme Procedure: eval exp module_or_state
C Function: scm_eval (exp, module_or_state)
Evaluate exp, a list representing a Scheme expression, in the top-level 
environment specified by module_or_state. While exp is evaluated (using 
primitive-eval), module_or_state is made the current module. The current module 
is reset to its previous value when eval returns. XXX - dynamic states. 
Example: (eval ’(+ 1 2) (interaction-environment))

Note that ‘eval’ does not even have a default environment, you need to specify 
an environment (in this case, a module) to evaluate the expression in! So, an 
option here is to let (guile) be the current messy (not recommended) 
environment, let (guile interaction-environment-2) (*) be a cleaned-up version, 
if at some point in time it is decided this cleaned-up version is not clean 
enough or that some bindings should be added, a new module (guile 
interaction-environment-3) could be defined, etc..

(Important point: never change the contents of one of these interaction 
environment modules, to ensure compatibility!)  (If at some point there are too 
many of these interaction environment, the old ones can be moved to separate 
libraries to be installed with the local package manager – this might even 
include (guile).)

This way, any user of ‘eval’ or the like can (and in case of ‘eval’, needs to) 
specify _which_ environment they want.

Next, we have the thunk ‘interaction-environment’:

>Scheme Procedure: interaction-environment
>C Function: scm_interaction_environment ()
>Return a specifier for the environment that contains implementation–defined 
>bindings, typically a superset of those listed in the report. The intent is 
>that this procedure will return the environment in which the implementation 
>would evaluate expressions dynamically typed by the user.

For compatibility, this would need to be the messy (guile) module. It would 
also need to deprecated (but not actually removed) – best let users specify 
_which_ version they want, so compatibility is preserved.

Next there is ‘eval-string’ and ‘primitive-eval’, which evaluates in the 
current module (and hence doesn’t care about what is the interaction 
environment).

There is also “guile -l [...]” and the like, but I don’t think Lilypond and the 
like really care about what “guile -l [...]” uses as default environment, as 
long as there is a way of overriding the choice.

Also, on deprecation and removal: just because you deprecate something, doesn’t 
mean it has to be removed. And just because something deprecated will be 
removed or because something is volatile, doesn’t mean it has to be an 
incompatible change! 

We can do something similar to what Coq does – Coq sometimes does incompatible 
changes, but at the same time, when it does so, it also verifies that there are 
no impacted libraries, and if there are impacted libraries, the impacted 
libraries are first modified – by people making changes to Coq itself(*) – to 
update it according to the changes.  (It’s not done for _all_ libraries of 
course, but still a nice selection.)

(*) Actually I’m not sure if this about Coq itself or a selection of Coq 
libraries, but the point stands either way.

Also, in RnRS modules can have version modules. There isn’t currently support 
for defining multiple versions of modules in Guile, but there could be.

Best regards,
Maxime Devos.


RE: The Guile junk drawer and a C plea (was: [PATCH] Addnondestructive delq1, delv1, and delete1.)

2024-06-29 Thread Maxime Devos
>However, I personally hope that Guile will continue to be friendly towards 
>those using it as an embedded language. There, a C API is important. There 
>*is* a downside in moving to Scheme from that perspective, but that is fine as 
>long as it is easy to call Scheme from C. The typical use case is when a 
>binding in the application which use Guile as embedded language needs to 
>manipulate Scheme data in its arguments in order to interpret them.

Currently, there is some code to automatically generate Scheme bindings to C 
procedures (i.e. automatically generated scm_c_define_gsubr) (IIRC this is 
‘snarfing’, but maybe that’s only a documentation thing).

It is possible to call the Scheme procedures from C (scm_call + module 
reflection API to get the procedure), but AFAIK there is no mechanism yet for 
_automatically_ generating the C wrappers to Scheme things yet. For the 
embedded language case, it would be useful to have such an automatic generator.

Best regards,
Maxime Devos.