JavaScript Type Declarations

H

Hubert Kauker

In a recent article about higher order JavaScript functions I found
the following example:

function testFor( fn ) {
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

Oops, I said to myself, what is this function doing?

Its argument fn is supposed to be a function, as its name fn and the
article's context
made sufficiently clear.
More precisely, reading the code reveals that it is supposed to be a
Boolean valued
function taking any Object argument. Right?
And what is the return function?
Clearly, it is a Boolean valued function taking any number of Object
arguments.
Note that "any number of ..." is quite different from "an array
of ...".

Well, good practice requires always to write comment in one's
projects, even on seemingly innocent and straightforward code.
It makes time consuming reasoning absolutely superfluous.

How could we comment the above example?
There are several ways.

First of all, we might write the usual kind of half-formalized prose:

@param fn a Boolean valued function of any Object

@return a Boolean valued function of any number of Objects which
returns true
as soon as fn sequentially applied to one of the given objects
returns true.
Attention: fn should not have side effects since it may not be
applied to
all given objects.

That requires a lot of reading, too.

Well, JavaScript has no formalism to write down type declarations, let
alone
type declarations for functions.

But we might use comments to write

Boolean Function(Object)

to denote the parameter type, and

Boolean Function( Object ... )

to denote the return type.

Note how I use "Type ..." to denote "any number of Type",
and to denote "array of Type" I would use "Type[]".

So, our example then might read like this.

/* Boolean Function( Object ... ) */
function testFor( /* Boolean Function( Object ) */ fn )
{
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

Outside the "function" keyword I write down the type of the return
value.
Inside the parameter list, each parameter is preceded by its own type,
and I would recommend to do that even if it were a simple type like
Object, Number, Date, or any other, even self defined, by which I mean
an instance of a self defined constructor function.

That is already pretty much clearer, isn't it?

And what is the type of the higher order function testFor itself?
This might be useful, if testFor itself were used as an argument in
another
function of even higher order.
So, here it is:

(Boolean Function( Object ... )) Function( Boolean Function( Object ))

== Arrow Notation ==

The above notation of function types might be called "functional",
because it
contains the Function keyword and the usual parentheses.
It is certainly intuitive in simple cases.
But it is not so easy to read in complex cases because of its many
redundant parts.

Therefore I am looking for a less cluttered notation which can be read
even better
for more complex higher order functions.
We shall convert from function notation to arrow notation.

Instead of writing

ReturnType Function( ParameterType )

we might just as well write

ParameterType -> ReturnType

Here the two-character sequence "->" is meant to faintly resemble an
arrow.
The advantage is that we can omit the Function keyword and the
parentheses.

Then our above type of testFor reads:

(Object -> Boolean) -> ((Object ... ) -> Boolean)

Of course, the complexity of this type requires that internal
parentheses are still being used.

However, since none of this notation is official JavaScript, it always
has to be placed inside comments.
So it does not really matter which alternative we choose, as long as
we make ourselves sufficiently clear.
So our above example might also be written like this.

/* (Object ... ) -> Boolean */
function testFor( /* Object -> Boolean */ fn )
{
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

That is pretty easy to read, I think.
Of couse, some further comment to this function might still be in
order, such as the warning about
side effects and the order of evaluation.

What do you think?
Do you practice a similar approach or do you know of other schemes?

Hubert
 
T

Thomas 'PointedEars' Lahn

Hubert said:
In a recent article about higher order JavaScript functions I found
the following example: [...]

Is there also a legible variant of your posting?


PointedEars
 
H

Hubert Kauker

Is there also a legible variant of your posting?

I am reading this posting in Firefox, and it looks quite ok.
Even the indented parts of the function.

What specifically are you hinting at?

Hubert
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]>, Mon,
24 Aug 2009 10:59:17 said:
Hubert said:
In a recent article about higher order JavaScript functions I found
the following example: [...]

Is there also a legible variant of your posting?
^^^^^^^

You really are obnoxious. It is to be hoped that you will not succeed
in driving HK away. Perhaps HK can advise you about the provision of
mental health services in Germany; another Kaiser is not needed.

It's rather amusing that, in criticising HK's way of expressing himself
in English, you yourself write faulty English. HK's article is exactly
as legible, to each of us, as all other articles (apart from those in
HTML); legibility is a matter of the distinctness of the displayed
glyphs, and has nothing to do with the selection of the characters which
they express.

HK's English is, perhaps, not quite as elegantly effective as that of,
for example, Winston S Churchill [1], but, for those who really know the
language, it presents no significant problems.


HK:

Function testFor apparently processes a variable number of arguments
with its first argument, until one is "liked". Possibly its for loop
start with an index of 1.

Argument fn can, in testFor, be given an argument of any type. But it
is not necessarily intended that a specific instance of fn need be
capable of usefully handling all types of argument; it is only necessary
that the arguments of testFor, up to and including the one that is
"liked", or the end, should be compatible with the fn of that call.

One must consider side-effects of fn; but I see no reason to ban them.

You have function testFor( /* Boolean Function( Object ) */ fn )
Where it can be used, I think // comment is better; it does not fragment
the code, and on seeing its beginning one knows instantly where it ends.

Using Tab to indent is deprecated in News; I find two (or three) spaces
generally better and easier on the eyes.

When documenting languages or programs or anything else, one must
consider who is to read the material. Within a closed group, such as a
language development team, it is possible to have an efficient compact
notation which has to be taught and learned. But where the group is not
closed, documentation should require no more than an understanding of
the natural language used. That is why the FAQ is wrong in introducing
(and without explanation) an "@param" notation.



[1] An exception to the normal English omission of middle initials; but
he had good cause, as explained in the chapter "Oldham" of his "My Early
Like" (recommended to those with a sense of humour) - and he was of
semi-US descent.
 
A

Andrew Poulos

JR said:
"borken"?

From wikipedia: Borken or b0rken is internet slang for "broken," often
referring to a computer program or a feature of a program that is not
working as expected.

Andrew Poulos
 
J

JR

 From wikipedia: Borken or b0rken is internet slang for "broken," often
referring to a computer program or a feature of a program that is not
working as expected.

Andrew Poulos

Thanks. But "paragraphs are borken" might not be a good "posting
style" recommendation.
 
G

Garrett Smith

Hubert said:
In a recent article about higher order JavaScript functions I found
the following example:

function testFor( fn ) {
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

Oops, I said to myself, what is this function doing?


This returns a function that tests an argument list and returns
undefined or, if -fn- returns true for any argument, a boolean - true -.

Who calls that function and what do they use it for.

Whatever it is, it could be better.
Its argument fn is supposed to be a function, as its name fn and the
article's context

Calling something that is not [[call]]able would result in an error,
functions are callable, but there are other things that are callable,
too. Regexp, in SPidermonkey, for example:

/a/('a');
made sufficiently clear.
More precisely, reading the code reveals that it is supposed to be a
Boolean valued
function taking any Object argument. Right?


No, it's a tester function. - testFor - is to test to see if the
argument list contains an argument for which - fn - will return true.

That function uses - arguments - but could use an array instead. i.e.
instead of:-

testFor(obj1, obj2, obj3);
- use: -

testFor([obj1, obj2, obj3]);

Some implementations will make an optimization, based on a lexical scan
of the function. If it does - arguments - or - eval -, an arguments
object won't be created.
And what is the return function?

Sounds like your' e asking about the return statement returning a function.

That function returns a function. The returned function has fn up the
scope chain that contains - fn - which it uses.
Clearly, it is a Boolean valued function taking any number of Object
arguments.

There is no test of the value returned whatsoever. The value returned
gets passed to [[ToBoolean]] in the - if - statement.

Not only is - fn - not required to return boolean, the returned function
(that calls fn) returns boolean or undefined.
Note that "any number of ..." is quite different from "an array
of ...".

Well, good practice requires always to write comment in one's
projects, even on seemingly innocent and straightforward code.
It makes time consuming reasoning absolutely superfluous.

How could we comment the above example?

I would reformat to spaces and mention the issues in comments that I
think are bad ideas. They are:
* variant return type,
* questionable pattern usage
* use of - arguments - object

[postulation about type annotated comments]

What do you think?

That function is unclear, formatted with tabs, and doesn't have a
consistent return type. What ever it is being used for, and I don't know
what that is, but hwatever it is, it could be done better. More clearly
and probably a lot more efficiently.

Since you didn't provide one, here is an example of that function:-

function catchFish(fisherman){
return fisherman.luck > .9;
}

function Fisherman(i){
this.luck = Math.random();
};

var fishermen = [];
for(var i = 0; i < 5; i++) {
fishermen.push(new Fisherman(i));
}

function testFor( fn ) {
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

typeof testFor(catchFish).apply(null, fishermen);

You can get better luck by adding more fisherman or changing "catchFish".
Do you practice a similar approach or do you know of other schemes?

Commenting things that are obvious just so that JSDoc Toolkit would pick
it up made the code less readable. Code that is littered with many long
comments can be harder to read.

I decided that code readability was more important than documentation.

Clear variable names, simple functions that do only one thing. I comment
what is unclear, or complicated. I comment browser issues with an
example, where possible, e.g.

// XXX Opera 1.3 needs a non-empty string; it won't set attribute if
// second argument is "", so we use setAttribute(x, ";");

Long functions are harder to follow and just adding comments won't help
much.

Closures are an exception to the "short functions" rule. These functions
provides a lexical scope and does nothing else. They aren't procedures;
they're functions used solely for the scope they provide.

In javascript, function calls are more expensive than property access.
This is usually only an issue in loops, animation, or mousemove.
Refactoring a long function to many smaller ones usually helps
readability, but this can come at a cost of performance and in a
performance-critical function, it can be worth careful reconsideration.

Garrett
 
L

Lasse Reichstein Nielsen

Hubert Kauker said:
So, our example then might read like this.

/* Boolean Function( Object ... ) */
function testFor( /* Boolean Function( Object ) */ fn )
{
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}


You are really just doing type annotation. You can do better, if you
want good documentation.

You might use a notation similar to Java's JavaDoc. That already
exists, e.g., http://jsdoc.sourceforge.net/
Instead of writing

ReturnType Function( ParameterType )

we might just as well write

ParameterType -> ReturnType

Warms my old SML programmer's heart :)
What do you think?
Do you practice a similar approach or do you know of other schemes?

I've seen JSDoc used (but haven't really used it myself).

/L
 
B

Bruno Desthuilliers

Hubert Kauker a écrit :
In a recent article about higher order JavaScript functions I found
the following example:

function testFor( fn ) {
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

Oops, I said to myself, what is this function doing?


Seems quite obvious. So obvious, in fact, that I personnaly find it more
readable in the above form than in any natural language description I
could provide.

(snip long post)
So our above example might also be written like this.

/* (Object ... ) -> Boolean */
function testFor( /* Object -> Boolean */ fn )
{
return function() {
for( var i = 0; i < arguments.length; i++ ) {
if( fn( arguments ) ) return true;
}
};
}

That is pretty easy to read, I think.


That's only line noise IMHO.
Of couse, some further comment to this function might still be in
order, such as the warning about
side effects and the order of evaluation.

What do you think?

That you're wasting your time.
Do you practice a similar approach

Good god, hopefully not.
or do you know of other schemes?

yes : only write useful comments - stuff like references to the specs or
the explanation of a known algorithm, or eventually explanations about
non-obvious or sub-optimal implementation points, so the maintainer at
least has a chance to understand why this particular piece of code is
written that way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top