- Feature Name: module_reorg
- Start Date: 2018-05-31
- RFC PR: #20
- Neon Issue: neon-bindings/neon#324
A re-organization of the modules in neon::*
, designed to optimize:
- The learnability and understandability of the API docs;
- The convenience of importing from Neon;
- Names that reflect abstractions of the JavaScript language (e.g., values and execution contexts), instead of the JavaScript engine (e.g., memory management and VMs).
The current organization of Neon's modules makes it both difficult to know where to find APIs and inconvenient to import them.
This RFC proposes two major changes:
- Create a
neon::prelude
module that re-exports the most commonly-needed APIs, so that most projects can get away with just using:
use neon::prelude::*;
- Reorganize the APIs into smaller but non-nested modules, each oriented around a tightly-defined concept that matches a user's intuition.
The "prelude pattern" is very popular in the Rust ecosystem. It's especially convenient for newcomers just getting started with an API, for tutorials and presentations, and for rapid prototyping. But it's perfectly appropriate for production use as well.
Organizing the APIs into smaller modules makes it easier to guess and to remember where a particular API is defined. Avoiding hierarchical nesting also makes it easier to remember, since it doesn't require remembering the entire nested path from the Neon crate root.
For guides, this radically simplifies introductions to the Neon API, since today's large sequences of use
declarations can be replaced with a single use neon::prelude::*
.
Each public module can be explained like so:
neon::context
: Node execution contexts, which manage access to the JavaScript engine at various points in the Node.js runtime lifecycleneon::result
: Types and traits for working with JavaScript exceptionsneon::borrow
: Types and traits for obtaining temporary access to the internals of JavaScript valuesneon::handle
: Safe handles to managed JavaScript memoryneon::types
: Representations of JavaScript's core builtin typesneon::object
: Traits for working with JavaScript objectsneon::task
: Asynchronous background tasks that run in the Node thread poolneon::meta
: Utilities exposing metadata about the Neon version and buildneon::prelude
: A convenience module that re-exports the most commonly-used Neon APIs
This section describes the organization of each public module in detail.
Context
,CallContext
,FunctionContext
,MethodContext
,ComputeContext
,ExecuteContext
,ModuleContext
,TaskContext
CallKind
Lock
(renamed fromVmGuard
)
NeonResult
(renamed fromVmResult
),JsResult
,JsResultExt
,Throw
Borrow
,BorrowMut
,Ref
,RefMut
,LoanError
Handle
,Managed
DowncastError
,DowncastResult
JsArray
,JsArrayBuffer
,JsBoolean
,JsBuffer
,JsError
,JsFunction
,JsNull
,JsNumber
,JsObject
,JsString
,JsUndefined
,JsValue
JsResult
Value
BinaryData
,BinaryDataViewType
StringOverflow
,StringResult
Class
,ClassDescriptor
Object
,PropertyKey
This
Task
No changes.
// excludes: Lock
pub use neon::context::{Context, CallContext, FunctionContext, MethodContext, ComputeContext, ExecuteContext, ModuleContext, TaskContext, CallKind};
// excludes: Throw
pub use neon::result::{NeonResult, JsResult, JsResultExt};
// excludes: Managed, DowncastError, DowncastResult
pub use neon::handle::Handle;
// excludes: Ref, RefMut, LoanError
pub use neon::borrow::{Borrow, BorrowMut};
// excludes: BinaryDataViewType, StringOverflow, StringResult
pub use neon::types::{JsArray, JsArrayBuffer, JsBoolean, JsBuffer, JsError, JsFunction, JsNull, JsNumber, JsObject, JsString, JsUndefined, JsValue, JsResult, Value, BinaryData};
// excludes: PropertyKey, This, ClassDescriptor
pub use neon::object::{Class, Object};
pub use neon::task::Task;
// excludes: neon::meta::*;
I'm not a huge fan of the hoity-toity name "prelude," but it's a Rust community convention so it's best to stick with convention.
We could do nothing, but experience shows that it's pretty hard to keep track of what goes where. And we really need to get rid of named concepts like scope
and vm
, which are low-level, daunting, and confusing for people who've never dug deep into programming language or engine implementation concepts.
I experimented with a couple of alternative organization schemes as well:
- Almost completely flat: Everything except for
thread
andmeta
goes into the Neon top-level. Unfortunately this makes the API docs really overwhelming and hard to navigate. - Moderately layered: This attempts to divide the world into a "VM" abstraction layer and a "JS" abstraction layer. I found it very hard to explain these layers or to figure out how to sort the various definitions into one or the other layer.
At the end of the day, I think it's best explained as: Neon is offering a single abstraction layer, which roughly corresponds to the JavaScript language semantics, but with a couple of extra concepts (namely: handles and contexts) for making interaction with it safe. Within that single layer, there are a number of (interrelated) concepts, and it's helpful to group the API by those concepts.
None.