| Type | Bug | Status | tested | Date | 30-Jun-2010 22:11 |
|---|---|---|---|---|---|
| Version | alpha 99 | Category | Datatype | Submitted by | BrianH |
| Platform | All | Severity | major | Priority | high |
| 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 to | n/a | Fixed in | alpha 108 | Last Update | 2-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 | - |