REBOL3 tracker
  0.9.12 beta
Ticket #0001628 User: anonymous

Project:

Previous Next
rss
TypeBug Statustested Date30-Jun-2010 22:11
Versionalpha 99 CategoryDatatype Submitted byBrianH
PlatformAll Severitymajor Priorityhigh

Summary Inline modules inherit bindings (fix in MODULE)
Description When working on the module system, conversations with Carl implied that the body block passed to MAKE module! was unbound and deep-copied before being passed on to MAKE-MODULE. The test code below shows that to not be the case. The lack of a deep-copy can be acceptable because of how large module bodies are, though it makes reusing module bodies with the EXPORT keyword awkward, but the binding issues are a real problem.

This is a design issue and a major one. We need to decide whether inline modules act like regular modules, completely independent of each other.

The module system and planned preprocessor are currently designed around the principle of inline and script modules being equivalent in binding behavior, with the only difference being that the Needs header is not processed for inline modules (#1186). If the binding model is different between them then the preprocessor will need to add new code to make them equivalent. It could also be a gotcha if the difference is not well documented.

The current behavior would have increased flexibility, and some might consider that to be an advantage, especially if they want to override MAKE-MODULE with their own module system. However, that increased flexibility would come at the cost of fewer bugs being caught by the system.

Fixing this would mean adding one UNBIND/deep call to MAKE-MODULE. Fixing this with flexibility and no overhead to non-inline modules would mean adding the UNBIND/deep call to the MODULE function instead. Or we could just document the gotcha. We need to decide.
Example code
; Regular module, undefined words trigger errors (good)
>> do "rebol [type: module] attempt [z: 12345] print error? try [z]"
Module: "Untitled" Version: none Date: none
true

; Inline module, undefined words inherit from container (bad)
>> do "rebol [] module [] [attempt [z: 12345] print error? try [z]]"
false

; Note that the module body is modified if there are export keywords
>> module [] a: [export 'b] a
== ['b]

Assigned ton/a Fixed inalpha 108 Last Update2-Nov-2010 00:55


Comments
(0002414)
BrianH
30-Jun-2010 22:43

Personally, of the three possible fixes I prefer the unbind in MODULE solution. It would have the greatest flexibility, and the least gotchas.
(0002415)
maxim
30-Jun-2010 22:44

We should unbind even inline modules.

Otherwise, they become almost (exactly?) the same as objects.

So I don't see the point in even supporting inline modules, if they don't implement the differentiating features of modules.
(0002416)
BrianH
30-Jun-2010 23:11

Inline modules are useful even with a subset of the module features (no Needs header processing) because otherwise you can't bundle a bunch of modules together into one script/module, such as when you encap a project. The preprocessor needs an equivalent target model to generate to. Resolving the Needs header can be done statically by a preprocessor - this is why inline modules don't process Needs in the first place. However, without unbinding the bodies this kind of encapping would result in a combined script with different semantics than the separated scripts, and that just won't work.

We need to decide which of the 3 fixes we need to do:
- UNBIND/deep the whole spec in MAKE-MODULE, at the beginning (trivial)
- UNBIND/deep the whole spec in MODULE, after the REDUCE (trivial)
- Document the gotcha thoroughly in the module docs, answer the questions about the gotcha over and over again until R4 comes out, and require preprocessors to add the code to unbind the header and body explicitly to their results (difficult).

I prefer the second choice, putting the UNBIND/deep in MODULE. This would avoid adding the UNBIND/deep overhead to regular modules, which aren't bound in the first place, and give advanced users a choice to write their own module systems with their own binding rules. Any other votes?
(0002417)
maxim
30-Jun-2010 23:54

I second brian's choice of second method :-).
(0002432)
Carl
7-Jul-2010 01:26

These standard R3 rules apply to this ticket:

1. By default, bodies are bound in definitional layers. Therefore, if a block has been bound via a prior load (or other action) then those bindings serve as the basis for subsequent bindings. This applies not just to inline modules, but also to functions and objects. It is a consistent easy-to-remember rule.

2. By default, bodies are not deep copied. This also applies to modules, functions, and objects. The task of deep copy is assigned to mezzanine helper functions, such as FUNCTION and FUNC. There are advantages to not deep copying -- such as the case where boot-based mezz functions are not deep copied to save memory and time.

Therefore, the question is as BrianH put it: what is the correct application of these rules to an inline module? The answer is: the same as the other datatypes, it depends on the creation method. If MAKE is used, then we use existing bindings with no deep copy. However, if the MODULE function is used, then like FUNC, we can define a heavier behavior.

The final objective is to provide a method of combining multiple modules inline using the MODULE helper function. And, we would want the same semantics as if those modules were separately imported. Plus, the user can always use MAKE module! if some other behavior is desired.

Therefore, I agree on the second method above. Add UNBIND to MODULE.

(Sorry about the long reply, but it properly sets up the decision history for future "reflection".)
(0002744)
BrianH
2-Nov-2010 00:55

Problem solved in #1682.

Date User Field Action Change
2-Nov-2010 00:55 BrianH Comment : 0002744 Added -
20-Oct-2010 11:33 BrianH Summary Modified Inline modules inherit bindings => Inline modules inherit bindings (fix in MODULE)
20-Oct-2010 11:33 BrianH Fixedin Modified => alpha 108
20-Oct-2010 11:33 BrianH Status Modified reviewed => tested
7-Jul-2010 01:27 carl Status Modified submitted => reviewed
7-Jul-2010 01:26 carl Comment : 0002432 Added -
30-Jun-2010 23:54 maxim Comment : 0002417 Added -
30-Jun-2010 23:11 BrianH Comment : 0002416 Added -
30-Jun-2010 22:44 maxim Comment : 0002415 Added -
30-Jun-2010 22:43 BrianH Comment : 0002414 Added -
30-Jun-2010 22:13 BrianH Description Modified -
30-Jun-2010 22:13 BrianH Code Modified -
30-Jun-2010 22:11 BrianH Ticket Added -