[gjs] docs: Review and modernize docs



commit a00f84f67deea14c30fa3d98e1ff76ce931c0aa9
Author: Philip Chimento <philip chimento gmail com>
Date:   Tue Nov 29 23:33:48 2016 -0800

    docs: Review and modernize docs
    
    Some of the docs were definitely out of date. Also, I split out the
    section on JavaScript inheritance from Style_Guide.md since it had become
    quite overgrown, into its own file.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=595439

 doc/Class_Framework.md     |   98 +++++++++++++++++++++++++++++++++++++
 doc/SpiderMonkey_Memory.md |   12 +++-
 doc/Style_Guide.md         |  116 ++------------------------------------------
 3 files changed, 112 insertions(+), 114 deletions(-)
---
diff --git a/doc/Class_Framework.md b/doc/Class_Framework.md
new file mode 100644
index 0000000..53db239
--- /dev/null
+++ b/doc/Class_Framework.md
@@ -0,0 +1,98 @@
+# Class framework #
+
+Keep in mind that JavaScript does not "really" have classes in the sense of C++ or Java; you can't create 
new types beyond the built-in ones (Object, Array, RegExp, String). However, you can create object instances 
that share common properties, including methods, using the prototype mechanism.
+
+Every JavaScript implementation invents its own syntactic sugar for doing this, and so did we, but the 
basics are always the same.
+In ES6, JavaScript finally went ahead and standardized some particular syntactic sugar, which GJS will 
support in the future.
+
+Each JavaScript object has a property `__proto__`; if you write `obj.foo` and `foo` is not in `obj`, 
JavaScript will look for `foo` in `__proto__`. If several objects have the same `__proto__`, then they can 
share methods or other state.
+
+You can create objects with a constructor, which is a special function. Say you have:
+```js
+function Foo() {}
+let f = new Foo();
+```
+
+For `new Foo()` JavaScript will create a new, empty object; and execute `Foo()` with the new, empty object 
as `this`. So the function `Foo()` sets up the new object.
+
+`new Foo()` will also set `__proto__` on the new object to `Foo.prototype`. The property `prototype` on a 
constructor is used to initialize `__proto__` for objects the constructor creates. To get the right 
`__proto__` on objects, we need the right prototype property on the constructor.
+
+You could think of `f = new Foo()` as:
+```js
+let f = {}; // create new object
+f.__proto__ = Foo.prototype; // doing this by hand isn't actually allowed
+Foo.call(f); // invoke Foo() with new object as "this"
+```
+
+Our syntactic sugar is `Lang.Class` which works like this:
+```js
+const Lang = imports.lang;
+
+const Foo = new Lang.Class({
+  Name: 'Foo',
+  _init: function(arg1, arg2) {
+    this._myPrivateInstanceVariable = arg1;
+  },
+  myMethod: function() {
+
+  },
+  myClassVariable: 42,
+  myOtherClassVariable: "Hello"
+}
+```
+
+This pattern means that when you do `let f = new Foo()`, `f` will be a new object, `f.__proto__` will point 
to `Foo.prototype` which will be the object that you passed to `new Lang.Class()`, and `Foo.prototype._init` 
will be called to set up the object.
+
+> **NOTE:** Again, on the JavaScript language level, Foo is not a class in the sense of Java or C++; it's 
just a constructor function, which means it's intended for use with the `new Foo()` syntax to create an 
object. Once the object is created, from a JavaScript language perspective its type is the built-in type 
`Object` - though we're using it and thinking of it as if it had type `Foo`, JavaScript doesn't have a clue 
about that and will never do any type-checking based on which constructor was used to create something. All 
typing is "duck typing." The built-in types, such as `Object`, `String`, `Error`, `RegExp`, and `Array`, 
_are_ real types, however, and do get type-checked.
+
+> **NOTE:** If a constructor function has a return value, it is used as the value of `new Foo()` - replacing 
the automatically-created `this` object passed in to the constructor. If a constructor function returns 
nothing (undefined), then the passed-in `this` is used. In general, avoid this feature - constructors should 
have no return value. But this feature may be necessary if you need the new instance to have a built-in type 
other than Object. If you return a value from the constructor, `this` is simply discarded, so referring to 
`this` while in the constructor won't make sense.
+
+## JavaScript "inheritance" ##
+
+There are lots of ways to simulate "inheritance" in JavaScript. In general, it's a good idea to avoid class 
hierarchies in JavaScript. But sometimes it's the best solution.
+
+Our preferred approach is to use our syntactic sugar `Lang.Class` which includes an `Extends` property which 
sets the prototype of the subclass to the base class. Looking up a property in the subclass starts with the 
properties of the instance. If the property isn't there, then the prototype chain is followed first to the 
subclass's prototype and then to the base class's prototype.
+```js
+const Lang = imports.lang;
+
+const Base = new Lang.Class({
+  Name: 'Base',
+  _init : function(foo) {
+    this._foo = foo;
+  },
+  frobate : function() {
+  }
+});
+
+const Sub = new Lang.Class({
+  Name: 'Sub',
+  Extends: Base,
+  _init: function(foo, bar) {
+    // here is an example of how to "chain up"
+    this.parent(foo);
+    this._bar = bar;
+  }
+
+  // add a newMethod property in Sub.prototype
+  newMethod : function() {
+  }
+});
+```
+
+> **NOTE:** You cannot use this mechanism to inherit from a built-in type, such as String or Error, because 
the methods on those objects expect them to have primitive type String or Error, while your constructor will 
create an Object instead.
+
+In portable JavaScript code you'll often see a different technique used to get this prototype chain:
+```js
+function Base(foo) ...
+
+Base.prototype = ...
+
+function Sub(foo, bar) ...
+
+// Do NOT do this - do not use an instance of Base as the Sub prototype
+Sub.prototype = new Base();
+```
+
+The problem with this pattern is that you might want to have side effects in the `Base()` constructor. Say 
`Base()` in its constructor creates a window on the screen, because `Base()` is a dialog class or something. 
If you use the pattern that some instances of `Base()` are just prototypes for subclasses, you'll get extra 
windows on the screen.
+
+The other problem with this pattern is that it's just confusing and weird.
diff --git a/doc/SpiderMonkey_Memory.md b/doc/SpiderMonkey_Memory.md
index 3fd73f0..5d4d072 100644
--- a/doc/SpiderMonkey_Memory.md
+++ b/doc/SpiderMonkey_Memory.md
@@ -1,8 +1,8 @@
 # Memory management in SpiderMonkey #
 
-When writing JavaScript extensions in C, we have to understand and be careful about memory management.
+When writing JavaScript extensions in C++, we have to understand and be careful about memory management.
 
-This document only applies to C code using the jsapi.h API. If you simply write a GObject-style library and 
describe it via gobject-introspection typelib, there is no need to understand garbage collection details.
+This document only applies to C++ code using the jsapi.h API. If you simply write a GObject-style library 
and describe it via gobject-introspection typelib, there is no need to understand garbage collection details.
 
 ## Mark-and-sweep collector ##
 
@@ -42,7 +42,10 @@ The general rule is that SpiderMonkey has a set of GC roots. To do the garbage c
 
 So if you have a `JS::Value` or `JSObject*`/`JSString*`/`JSFunction*` somewhere that is not reachable from 
one of SpiderMonkey's GC roots - say, declared on the stack or in the private data of an object - that will 
not be found. SpiderMonkey may try to finalize this object even though you have a reference to it.
 
-If you reference JavaScript objects from your custom object, you have to use `JS::Heap<T>` and set the 
`JSCLASS_MARK_IS_TRACE` flag in your JSClass, and define a trace function in the class struct. A trace 
function just invokes `JS_CallTracer()` to tell SpiderMonkey about any objects you reference. See [JSTraceOp 
docs][2].
+If you reference JavaScript objects from your custom object, you have to use `JS::Heap<T>` and set the 
`JSCLASS_MARK_IS_TRACE` flag in your JSClass, and define a trace function in the class struct. A trace 
function just invokes `JS_CallHeapValueTracer()`, `JS_CallHeapObjectTracer()`, etc. to tell SpiderMonkey 
about any objects you reference. See [JSTraceOp docs][2].
+
+Tracing doesn't add a GC thing to the GC root set!
+It just notifies the interpreter that a thing is reachable from another thing.
 
 ## Global roots ##
 
@@ -67,6 +70,9 @@ JSObject *obj = JS_New(cx, whatever, ...);
 
 This is what `JS::Rooted<T>` is for, and its specializations `JS::RootedValue`, `JS::RootedObject`, etc. 
`JS::Rooted<T>` adds its wrapped `T` to the GC root set, and removes it when the `JS::Rooted<T>` goes out of 
scope.
 
+Note that `JS::Rooted` can only be used on the stack.
+For optimization reasons, roots that are added with `JS::Rooted` must be removed in LIFO order, and the 
stack scoping ensures that.
+
 Any SpiderMonkey APIs that can cause a garbage collection will force you to use `JS:Rooted<T>` by taking a 
`JS::Handle<T>` instead of a bare GC thing. `JS::Handle<T>` can only be created from `JS::Rooted<T`>.
 
 So instead of the above code, you would write
diff --git a/doc/Style_Guide.md b/doc/Style_Guide.md
index 46852c5..1a91457 100644
--- a/doc/Style_Guide.md
+++ b/doc/Style_Guide.md
@@ -58,12 +58,12 @@ Inside functions, `let` is always correct instead of `var` as far as we know. `v
 the value of this where the closure is created, because `this` is a keyword with a value passed
 in at function invocation time, it is not a variable that can be captured in closures.
 
-To solve this, use `Lang.bind`, eg:
+To solve this, use `Function.bind()`, or fat arrow functions, e.g.:
 
 ```js
-const Lang = imports.lang;
-
-let closure = Lang.bind(this, function() { this._fnorbate() });
+let closure = function() { this._fnorbate() }.bind(this);
+// or
+let closure = () => { this._fnorbate(); };
 ```
 
 A more realistic example would be connecting to a signal on a
@@ -74,7 +74,7 @@ const Lang = imports.lang;
 
 MyPrototype = {
     _init : function() {
-       fnorb.connect('frobate', Lang.bind(this, this._onFnorbFrobate));
+       fnorb.connect('frobate', this._onFnorbFrobate.bind(this));
     },
 
     _onFnorbFrobate : function(fnorb) {
@@ -116,112 +116,6 @@ If your usage of an object is like a hash table (and thus conceptually the keys
 * No tabs.
 * If you `chmod +x .git/hooks/pre-commit` it will not let you commit with messed-up whitespace (well, it 
doesn't catch tabs. turn off tabs in your text editor.)
 
-## JavaScript "classes" ##
-
-Keep in mind that JavaScript does not "really" have classes in the sense of C++ or Java; you can't create 
new types beyond the built-in ones (Object, Array, RegExp, String). However, you can create object instances 
that share common properties, including methods, using the prototype mechanism.
-
-Each JavaScript object has a property `__proto__`; if you write `obj.foo` and `foo` is not in `obj`, 
JavaScript will look for `foo` in `__proto__`. If several objects have the same `__proto__`, then they can 
share methods or other state.
-
-You can create objects with a constructor, which is a special function. Say you have:
-```js
-function Foo() {}
-let f = new Foo();
-```
-
-For `new Foo()` JavaScript will create a new, empty object; and execute `Foo()` with the new, empty object 
as `this`. So the function `Foo()` sets up the new object.
-
-`new Foo()` will also set `__proto__` on the new object to `Foo.prototype`. The property `prototype` on a 
constructor is used to initialize `__proto__` for objects the constructor creates. To get the right 
`__proto__` on objects, we need the right prototype property on the constructor.
-
-You could think of `f = new Foo()` as:
-```js
-let f = {}; // create new object
-f.__proto__ = Foo.prototype; // doing this by hand isn't actually allowed
-Foo.call(f); // invoke Foo() with new object as "this"
-```
-
-Our pattern for writing classes is:
-```js
-function Foo(arg1, arg2) {
-  this._init(arg1, arg2);
-}
-
-Foo.prototype = {
-  _init : function(arg1, arg2) {
-    this._myPrivateInstanceVariable = arg1;
-  },
-  myMethod : function() {
-
-  },
-  myClassVariable : 42,
-  myOtherClassVariable : "Hello"
-}
-```
-
-This pattern means that when you do `let f = new Foo()`, `f` will be a new object, `f.__proto__` will point 
to `Foo.prototype`, and `Foo.prototype._init` will be called to set up the object.
-
-> **NOTE:** Again, on the JavaScript language level, Foo is not a class in the sense of Java or C++; it's 
just a constructor function, which means it's intended for use with the `new Foo()` syntax to create an 
object. Once the object is created, from a JavaScript language perspective its type is the built-in type 
`Object` - though we're using it and thinking of it as if it had type `Foo`, JavaScript doesn't have a clue 
about that and will never do any type-checking based on which constructor was used to create something. All 
typing is "duck typing." The built-in types, such as `Object`, `String`, `Error`, `RegExp`, and `Array`, 
_are_ real types, however, and do get type-checked.
-
-> **NOTE:** If a constructor function has a return value, it is used as the value of `new Foo()` - replacing 
the automatically-created `this` object passed in to the constructor. If a constructor function returns 
nothing (undefined), then the passed-in `this` is used. In general, avoid this feature - constructors should 
have no return value. But this feature may be necessary if you need the new instance to have a built-in type 
other than Object. If you return a value from the constructor, `this` is simply discarded, so referring to 
`this` while in the constructor won't make sense. }}
-
-## JavaScript "inheritance" ##
-
-There are lots of ways to simulate "inheritance" in JavaScript. In general, it's a good idea to avoid class 
hierarchies in JavaScript. But sometimes it's the best solution.
-
-Our preferred approach is to use a Spidermonkey-specific extension and directly set the `__proto__` member 
of the subclass's prototype to point to the prototype of the base class. Looking up a property in the 
subclass starts with the properties of the instance. If the property isn't there, then the prototype chain is 
followed first to the subclass's prototype and then to the base class's prototype.
-```js
-const Lang = imports.lang;
-
-function Base(foo) {
-  this._init(foo);
-}
-
-Base.prototype = {
-  _init : function(foo) {
-    this._foo = foo;
-  },
-  frobate : function() {
-  }
-};
-
-function Sub(foo, bar) {
-  this._init(foo, bar);
-}
-
-Sub.prototype = {
-  __proto__ : Base.prototype,
-
-  _init : function(foo, bar) {
-    // here is an example of how to "chain up"
-    Base.prototype._init.call(this, foo);
-    this._bar = bar;
-  }
-
-  // add a newMethod property in Sub.prototype
-  newMethod : function() {
-  }
-}
-```
-
-> **NOTE:** You cannot use this mechanism to inherit from a built-in type, such as String or Error, because 
the methods on those objects expect them to have primitive type String or Error, while your constructor will 
create an Object instead.
-
-> **NOTE:** You cannot use this mechanism to inherit from a GObject. For that to work, we would need to 
create a new GType in C that was a subclass of the base class GType, and we'd need to override the class 
methods in the new GType so they called into JavaScript. Tons of work. For now, GObject subclasses must be 
implemented in C.
-
-In portable JavaScript code you'll often see a different technique used to get this prototype chain:
-```js
-function Base(foo) ...
-
-Base.prototype = ...
-
-function Sub(foo, bar) ...
-
-// Do NOT do this - do not use an instance of Base as the Sub prototype
-Sub.prototype = new Base();
-```
-
-The problem with this pattern is that you might want to have side effects in the `Base()` constructor. Say 
`Base()` in its constructor creates a window on the screen, because `Base()` is a dialog class or something. 
If you use the pattern that some instances of `Base()` are just prototypes for subclasses, you'll get extra 
windows on the screen.
-
-The other problem with this pattern is that it's just confusing and weird.
-
 ## JavaScript attributes ##
 
 Don't use the getter/setter syntax when getting and setting has side effects, that is, the code:


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]