This repository was archived by the owner on Aug 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 87
draft about new lazy encoding #211
Open
bobzhang
wants to merge
3
commits into
source
Choose a base branch
from
lazy_encoding
base: source
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
--- | ||
title: Enhanced lazy encoding in BuckleScript | ||
--- | ||
|
||
|
||
|
||
Recently we made some significant improvements with our new encoding for lazy values and we find it so exciting that we want to highlight the changes. The new encoding generates very idiomatic JS output like hand-written ones. | ||
|
||
# What's the difference? | ||
|
||
Take this code snippet for example: | ||
|
||
```reasonml | ||
let lazy1 = lazy { | ||
"Hello, lazy" -> Js.log; | ||
1 | ||
}; // create a lazy value | ||
|
||
let lazy2 = lazy 3 ; // artifical lazy values for demo purpose | ||
|
||
Js.log2 (lazy1, lazy2); // logging the lazy values | ||
|
||
let (lazy la, lazy lb) = (lazy1, lazy2); // pattern match to force it evaluated | ||
|
||
Js.log2 (la, lb); // logging forced values | ||
``` | ||
|
||
Running this code in node, the output is as below: | ||
```bash | ||
lazy_demo$node src/lazy_demo.bs.js | ||
[ [Function], tag: 246 ] 3 # logging the output of two lazy blocks | ||
bobzhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Hello, lazy | ||
bobzhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1 3 | ||
``` | ||
|
||
With the new encoding, the output is as below: | ||
```bash | ||
bucklescript$node jscomp/test/lazy_demo.js | ||
{ RE_LAZY: 'todo', value: [Function: value] } # logging block one | ||
bobzhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ RE_LAZY: 'done', value: 3 } # logging block two | ||
Hello, lazy | ||
1 3 | ||
``` | ||
As you can see, with the new encoding, no magic tags like 246 appear, and the lazy status is clearly marked via `RE_LAZY: 'todo'` or `RE_LAZY: 'done'`. | ||
|
||
More than that, the generated code quality is also improved, in the old mode, the generated JS code is like this: | ||
|
||
```js | ||
var lazy1 = Caml_obj.caml_lazy_make((function (param) { | ||
console.log("Hello, lazy"); | ||
return 1; | ||
})); | ||
|
||
console.log(lazy1, 3); | ||
|
||
var la = CamlinternalLazy.force(lazy1); | ||
|
||
var lb = CamlinternalLazy.force(3); | ||
|
||
console.log(la, lb); | ||
|
||
var lazy2 = 3; | ||
``` | ||
|
||
In the new mode, it is much simplified: | ||
```js | ||
var lazy1 = { | ||
RE_LAZY: "todo", | ||
value: (function () { // internal function is using uncurried function for performance | ||
console.log("Hello, lazy"); | ||
return 1; | ||
}) | ||
}; | ||
|
||
var lazy2 = { | ||
RE_LAZY: "done", | ||
value: 3 | ||
}; | ||
|
||
console.log(lazy1, lazy2); | ||
|
||
var la = CamlinternalLazy.force(lazy1); | ||
|
||
var lb = CamlinternalLazy.force(lazy2); | ||
|
||
console.log(la, lb); | ||
``` | ||
|
||
## What changes do we make? | ||
|
||
In native, the encoding of lazy values is rather complicated: | ||
|
||
- It is an array, which is not friendly for debugging in JS context. | ||
- It has some special tags which is not meaningful, for example, magic number 246, in JS context. | ||
- It tries to unbox lazy values with the help of native GC, however, such complexity does not pay off in JS since JSVM does not expose its GC semantics. | ||
|
||
So in the master, our encoding scheme is much simplified to take advantage of JS as much as possible: | ||
|
||
- The encoding is uniform, it is always an object of two key value pairs, one is `RE_LAZY` to mark its status, | ||
the other is either a closure or an evaluated value. | ||
|
||
- The compiler optimization still kicks in at compile time: if it knows such lazy value is already evaluated or does not need to be evaluated, it will promote its status to be 'done'. However, unboxing is not happening unlike native. This makes sense since the most interesting unboxing scenarios happens in runtime instead of compile time where it is impossible in JSVM. | ||
|
||
|
||
With the new encoding, the lazy is a much nicer sugar and we encourage you to use it whenever it is convenient! | ||
|
||
# Caveats: | ||
|
||
Don't rely on the special name `RE_LAZY` for JS interop, we may change it to a symbol in the future. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.