Topic on Manual talk:Coding conventions/JavaScript

Code documentation: Distinguishing between object being compatible to interface by convention (duck typing) vs. requiring instance working with instanceof

4
Danwe (talkcontribs)

Recently I have been wondering how to document whether a object (e.g. required by a function's parameter) had to be an instance of a certain constructor vs. more basic requirement that it had to match a certain interface definition.

An example for this is jQuery.Promise. jQuery.Promise is no constructor but certainly is some sort of interface definition that you could do duck-type checks against.

Rather than just documenting that a parameter requires {Object}, we usually write {jQuery.Promise}. It is not clear though whether an instance of that constructor (in this case there is not even a constructor) is required or whether the object only had to stand duck-type checks against the interface. Is there any usual way how to add this information to the documentation? I could immagine something like jQuery.Promise^, so the ^ would imply that no real instance is required.

Mattflaschen (talkcontribs)

I would document it as {jQuery.Promise}. In fact, I have done so in a couple cases already. It is a documented type, and there's specific code implementing it. Based on the implementation and the target option of deferred.promise, I would describe jQuery.Promise as a mixin, rather than an interface.

Despite there being no Promise constructor, it's relatively easy to make a promise; for example, the caller can call the jQuery.Deferred constructor, then call deferred.promise. Technically, the second step is optional, as all Deferred objects are also Promise objects. However, calling .promise is necessary if you want to prevent external code from resolving your Promise.

Although duck-typing may work for Promise sometimes, I don't really see the need to advertise that in this case.

This post was posted by Mattflaschen, but signed as Superm401.

Danwe (talkcontribs)

Sorry, but this is not really what I wanted to know. Promise was just an example for something that can only be checked against by duck-typing and in documentation as some sort of "pseudo constructor" or concept, basically an interface definition.

You can't describe jQuery.Promise as a mixin since there is no jQuery.Promise. {jQuery.Promise} is just that conceptual thing we refer to documentation as described above. Besides, mixins are basically interfaces with implementation. Or you could argue behind each mixin there should be an interface conceptually.

So the question remains, how to document that something is rather referring to some concept rather than a real physical thing (a constructor).

Krinkle (talkcontribs)

While jQuery.Promise may (implementation-wise) not be a public constructor, I would most certainly consider it a class. In essence it is a private class in jQuery that various other classes inherit from by calling the private object constructor function for promises. And while that constructor is not exposed, the objects constructed from it are.

jQuery.Deferred objects mixin all public properties of the internally constructed promise. And deferred.promise() returns the promise object as-is. JavaScript doesn't really have classes to begin with anyway, and as such it is up to a constructor to decide whether to construct objects plainly (inheriting only from Object), or with additional prototypes in the chain. In the case of jQuery's promises, they are plain objects.

Anyway, in jsduck documentation nothing implies that it has to pass instanceof in execution context. It should however pass "instance of" conceptually (an object created by the class documented in jsduck under that name). The idea of "^" doesn't make sense in that case because for all intends and purposes the object is and must in fact be an instance of jQuery.Promise.

If the function you're documenting is invoked with a promise created by jQuery.Deferred (or its callers such as $.ready, jqXHR, jQuery.fn.promise etc.) then using jQuery.Promise seems most appropriate within the conventions of how we use jsduck.

If the function takes a compatible promise created by another library, then I agree we could have an abstract class definition for Promise that could be used for cases where you aren't dealing with promises made by jQuery per se. Be careful though with assuming what is part of a "standard" promises. The specification is still in flux. It's easy to assume you need a simple promise and end up relying on jQuery-specific behaviour.