JSDoc, type variables - jsdoc

Can we have type variables in JSDoc?
For example I want to define identity function:
/**
* #param {a} x
* #return {a}
*/
const id = x => x;
But when I use it with concrete types id(2), editor always complains that type number is not assignable to type a. I understand why, as in Haskell or other similar languages the lower cased names in annotation is treat as type variable, but JS views it as concert type.
So is there a way to define type variables in JSDoc?
PS: Yea, I know that there is TS and Flow, and I should use them in stead of playing with annotations, but the project I'm working on now is not ready to be migrated to TS, but in same time I want to make things as safe as possible using JS only.

I think you're asking for a type definition for a method where the #param type is always the same as the #return type?
Borrowing from the Closure Compiler's Wiki: Declaring a bounded generic type:
/**
* #param {A} x
* #template A
* #return {A}
*/
const id = (x) => x;
/** #type {string} */
let str='';
/** #type {number} */
let num=1;
str=id(true); // Type warning.
str=id('string'); // Type safe.
str=id(1234); // Type warning.
num=id(true); // Type warning.
num=id('string'); // Type warning.
num=id(1234); // Type safe.
Produces the following warnings:
JSC_TYPE_MISMATCH: assignment
found : boolean
required: string at line 16 character 0
str=id(true)
^
JSC_TYPE_MISMATCH: assignment
found : number
required: string at line 20 character 0
str=id(1234)
^
JSC_TYPE_MISMATCH: assignment
found : boolean
required: number at line 22 character 0
num=id(true)
^
JSC_TYPE_MISMATCH: assignment
found : string
required: number at line 24 character 0
num=id('string')

Related

Documenting parameters of Scala functions defined via val

When documenting parameters of methods with Scaladoc, we can write:
/** Is number even
* #param i number
* #return true if i is even, false otherwise
*/
def isEvenDef(i: Int) = i % 2 == 0
Which after generating the docs (e.g. via doc from sbt) yields nice documentation of the parameters (pointless in this example, but useful in general):
However, writing an analogous function via val and using the same documentation:
/** Is number even
* #param i number
* #return true if i is even, false otherwise
*/
val isEvenVal = (i: Int) => i % 2 == 0
The param does not seem to show in the generated documentation:
Is there a way do document the parameters for functions defined via val such that they show similarly to the parameters of methods defined via def?

execute function only once and cache value in scala

I have a function like so
def runOnce(request: Request): Future[Result] = {
}
When I call this runOnce function, if it has not been run, I want it to run some method and return that result. If it has been run, I just want it to return the original result (the request coming in will be the same).
I can do it if I have no param like so
lazy val hydratedModel = hydrateImpl(request)
future for efficient filtering
def fetchHydratedModel(): Future[HydratedModelRequest] = {
hydratedModel
}
How to do in first case?
There's a general solution to this problem, which is function memoization; for a pure function (one that has no side-effects - it will not work for non-pure functions), the result of a function call should always be the same for the same set of argument values. Therefore, an optimization is to cache the value on the first call and to return it for subsequent calls.
You can achieve this with something like the following (a memoization class for pure functions with a single argument, updated—see comment below—to make it thread-safe):
/** Memoize a pure function `f(A): R`
*
* #constructor Create a new memoized function.
* #tparam A Type of argument passed to function.
* #tparam R Type of result received from function.
* #param f Pure function to be memoized.
*/
final class Memoize1[A, R](f: A => R) extends (A => R) {
// Cached function call results.
private val result = scala.collection.mutable.Map.empty[A, R]
/** Call memoized function.
*
* If the function has not been called with the specified argument value, then the
* function is called and the result cached; otherwise the previously cached
* result is returned.
*
* #param a Argument value to be passed to `f`.
* #return Result of `f(a)`.
*/
def apply(a: A) = synchronized(result.getOrElseUpdate(a, f(a)))
}
/** Memoization companion */
object Memoize1 {
/** Memoize a specific function.
*
* #tparam A Type of argument passed to function.
* #tparam R Type of result received from function.
* #param f Pure function to be memoized.
*/
def apply[A, R](f: A => R) = new Memoize1(f)
}
Assuming that the function you're memoizing is hydrateImpl, you can then define and use runOnce as follows (note that it becomes a val not a def):
val runOnce = Memoize1(hydrateImpl)
runOnce(someRequest) // Executed on first call with new someRequest value, cached result subsequently.
UPDATE: Regarding thread-safety.
In reply to the comment from user1913596, the answer is "no"; scala.collection.mutable.Map.getOrElseUpdate is not thread-safe. However, it's fairly trivial to synchronize access, and I have updated the original code accordingly (embedding the call within sychronized(...)).
The performance hit of locking access should be negated by the improved execution time (assuming that f is nontrivial).
There are likely better ways to do this depending on your setup, but a simple solution is to do the following
private var model: Option[Future[HydratedModelRequest]] = None
def runOnce(request: Request): Future[Request] = {
if (model.isEmpty) {
model = hydrateImpl(request)
}
model.get
}
If the request is indeed the same for each call, another option would be to require the request implicitly and hydrate lazily.
implicit val request: Request
lazy val hydratedRequest: Future[HydratedModelRequest] = hydrateImpl(request)

Understanding Sets and Sequences using String checking as an example

I have a string which I would like to cross check if it is purely made of letters and space.
val str = "my long string to test"
val purealpha = " abcdefghijklmnopqrstuvwxyz".toSet
if (str.forall(purestring(_))) println("PURE") else "NOTPURE"
The above CONCISE code does the job. However, if I run it this way:
val str = "my long string to test"
val purealpha = " abcdefghijklmnopqrstuvwxyz" // not converted toSet
str.forall(purealpha(_)) // CONCISE code
I get an error (found: Char ... required: Boolean) and it can only work using the contains method this way:
str.forall(purealpha.contains(_))
My question is how can I use the CONCISE form without converting the string to a Set. Any suggestions on having my own String class with the right combination of methods to enable the nice code; or maybe some pure function(s) working on strings.
It's just a fun exercise I'm doing, so I can understand the intricate details of various methods on collections (including apply method) and how to write nice concise code and classes.
A slightly different approach is to use a regex pattern.
val str = "my long string to test"
val purealpha = "[ a-z]+"
str matches purealpha // res0: Boolean = true
If we look at the source code we can see that both these implementations are doing different things, although giving the same result.
When you are converting it to a Set and using the forAll, you are ultimately calling the apply method for the set. Here is how the apply is called explicitly in your code, also using named parameters in the anonymous functions:
if (str.forall(s => purestring.apply(s))) println("PURE") else "NOTPURE" // first example
str.forall(s => purealpha.apply(s)) // second example
Anyway, let's take a look at the source code for apply for Set (gotten from GenSetLike.scala):
/** Tests if some element is contained in this set.
*
* This method is equivalent to `contains`. It allows sets to be interpreted as predicates.
* #param elem the element to test for membership.
* #return `true` if `elem` is contained in this set, `false` otherwise.
*/
def apply(elem: A): Boolean = this contains elem
When you leave the String literal, you have to specifically call the .contains (this is the source code for that gotten from SeqLike.scala):
/** Tests whether this $coll contains a given value as an element.
* $mayNotTerminateInf
*
* #param elem the element to test.
* #return `true` if this $coll has an element that is equal (as
* determined by `==`) to `elem`, `false` otherwise.
*/
def contains[A1 >: A](elem: A1): Boolean = exists (_ == elem)
As you can imagine, doing an apply for the String literal will not give the same result as doing an apply for a Set.
A suggestion on having more conciseness is to omit the (_) entirely in the second example (compiler type inference will pick that up):
val str = "my long string to test"
val purealpha = " abcdefghijklmnopqrstuvwxyz" // not converted toSet
str.forall(purealpha.contains)

In scala, is a unary_ a method or a property?

Since the following are equivalent:
-2
2.unary_-
and since parentheses are optional for methods with no arguments, shouldn't
2.unary_-()
also evaluate to -2 ? Instead, I get:
error: Int does not take parameters
The book I'm working through says that unary_- is a method, though this error seems to suggest it is a property of Int. Is this correct?
Proceeding from evan058's advice, I decided to run an experiement:
class Myint1(n:Int) {
def unary_-() = -n /* method definition has parentheses */
}
class Myint2(n: Int) {
def unary_- = -n /* no parentheses in definition */
}
val n1 = new Myint1(3)
val n2 = new Myint2(3)
n1.unary_- /* prints -3 */
n2.unary_- /* also gives -3 */
n1.unary_-() /* prints -3 */
n2.unary_-() /* throws error: Int does not take parameters */
So unary_- is a method, not a property. The reason for the behavior is that there is a difference between a method definition with parentheses and without. Note that, expectedly, -n1 and -n2 both result in -3.

Records with similar fields in OCaml

In this answer, the suggested way of "attaching" meta information to types was using a record:
type _foo = ...
and foo = {n:_foo; m:meta}
but what if I have multiple types I'd like to wrap with meta information? Apparently all field names in record types must have different names, and writing:
type _foo = ...
and foo = {n:_foo; m:meta}
...
type _fooX = ...
and fooX = {nX:_fooX; mX:meta}
seems redundant :/. Classes are the only way to solve this? I'd like to avoid dealing with classes, if possible.
You can use parameterized type, perhaps.
type 'a wrapped = { base: 'a; extra: meta }
Jeffrey's solution is correct and scales perfectly to recursive types.
type location
type 'a loc = { a : 'a; loc : location }
type exp = Int of int | Add of exp loc * exp loc
It is still possible to use the previous two-time definition of your type,
as follows:
type exp_data = Int of int | Add of exp * exp
and exp = exp_data loc
Finally, a slightly different style is to use "open recursion", that is to define only an "derecursified type" open_exp with free parameters instead of recursive occurences. You can then get the recursive type back by taking the fixpoint; you can take different fixpoint, one with no additional information, and one with location interleaved for example. This is a generic construction to insert information at recursion sites, and its term-level counterpart allows for weaving different things in a recursive function (memoization, profiling, debug, etc.).
type 'e open_exp = Int | Add of 'e * 'e
type simple_exp = Simple of simple_exp open_exp
type located_exp = Loc of located_exp loc open_exp