My favorites | Sign in
Project Home Downloads Wiki Issues Source
New issue   Search
for
  Advanced search   Search tips   Subscriptions
Issue 822: Types not inferred through anonymous function idiom (IFFE)
3 people starred this issue and may be notified of changes. Back to list
Status:  Duplicate
Owner:  ----
Closed:  May 1

Restricted
  • Only users with Nobody permission may comment.


Sign in to add a comment
 
Reported by aaron.hamid, Sep 24, 2012
What steps will reproduce the problem?

Example:

namespace = {}

/** @constructor */
namespace.MyType1 = function() {};

(function() {
  /** @constructor */
  namespace.MyType2 = function() {};
})();

(function(ns) {
  /** @constructor */
  ns.MyType3 = function() {};
})(namespace);


/** @return {namespace.MyType1} */
function returnMyType1() {
  return new namespace.MyType1();
}

// "Bad type annotation"
/** @return {namespace.MyType2} */
function returnMyType2() {
  return new namespace.MyType2();
}

// "Bad type annotation"
/** @return {namespace.MyType3} */
function returnMyType3() {
  return new namespace.MyType3();
}

java -jar lib/compiler.jar --jscomp_error checkTypes --compilation_level SIMPLE_OPTIMIZATIONS test/type.js 
test/type.js:23: ERROR - Bad type annotation. Unknown type namespace.MyType2
/** @return {namespace.MyType2} */
             ^

test/type.js:29: ERROR - Bad type annotation. Unknown type namespace.MyType3
/** @return {namespace.MyType3} */
             ^

2 error(s), 0 warning(s)

(note: --compilation_level WHITESPACE_ONLY seems to circumvent typechecking)

What is the expected output? What do you see instead?

It would be nice if the compiler understood this idiom and could accommodate the dynamic definition of types on a globally-defined namespace (even if it requires some extra developer effort/annotation/convention), as this is a very common idiom with hand-written javascript.


What version of the product are you using? On what operating system?

java -jar lib/compiler.jar --version
Closure Compiler (https://code.google.com/closure/compiler)
Version: 20120917 (revision 2180)
Built on: 2012/09/17 14:33

Linux msi-cr620 3.4.9-2.fc16.x86_64 #1 SMP Thu Aug 23 17:51:29 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Fedora release 16 (Verne)

Please provide any additional information below.

I am experimenting with using closure-compiler as a standalone general-purpose javascript typechecker.  I understand this is not main goal of closure compiler but it already is so thorough, it would be nice to be able to reuse a lot of this work against hand-written javascript.  See: https://github.com/incandescent/closure-typechecker/
Sep 24, 2012
#1 aaron.hamid
This is related to (probably duplicates) #61
Sep 26, 2012
Project Member #2 Nicholas.J.Santos
Type2 duplicates  issue 61 .

Type3 is more interesting, so I think it is worth keeping this bug open for Type3.

The back story on this: inferring types is an active area of academic research. The problem is that to do "total" type inference in a dynamic language like javascript, the compiler might need to do arbitrary back-tracking, which could take a very, very long time (long enough that the compiler time would be unacceptably for large programs).  One of our recent committers did his PhD dissertation in this area, just to give a sense of the depth of the problem.

Closure Compiler solves this problem by trying a couple heuristics to infer in a specific order, so that it does not need to backtrack arbitrarily far. In this case, pulling "namespace" into the IFFE of Type3 is probably not something we can reasonably do in the general case.

I guess one way we could currently solve this is by special-casing the syntax of the IFFE around Type3, but this would be very brittle--it would only work for that exact syntax. So it would be helpful to know if that's the exact syntax you actually want Closure Compiler to handle, or if there are other IFFE syntaxes that are important.
Sep 26, 2012
#3 aaron.hamid
Thanks for the response Nick.  I am not an expert at all but it occurred to me checking types in a dynamic language like this could essentially be equivalent to the halting problem ;)

Could we special case it only for global (top-level) anonymous functions invoked exactly once and therefore assume any formal arguments are synonyms for their actual arguments?  I've been doing some debugging and I *think* it's resolving the right qualified property within the MyType3 block.

Another wrinkle with this idiom is that in a browser it is typically preceded with a conditional namespace definition which probably complicates things further:

if (typeof namespace === "undefined" || namespace === null) {
  namespace = {};
}

I think there are some annotation alternatives I haven't tested yet, and I think expecting additional assistance from the programmer here is fine as well.
Sep 26, 2012
Project Member #4 chadkill...@missouristate.edu
It's the recommended pattern for jQuery plugin development to pass the namespace into an immediately executed anonymous function.

(function($) {
  $()...
})(jQuery)

This case is discussed in  issue 448 . I'd still like to see this supported.
Sep 26, 2012
#5 aaron.hamid
Yes #448 is exactly what I am reporting with this issue as well, and I think some additional annotation support as Nick suggests early in the thread to be able to alias or type variables/parameters that I specifically know (or want to coerce to be) the right type, is right on target. (having the second MyType2 case above would also be nice but I think it is inferior style and a degenerate case of MyType3).
May 1, 2014
Project Member #6 blic...@google.com
Issue tracking has been migrated to github. Please make any further comments on this issue through https://github.com/google/closure-compiler/issues
Labels: Restrict-AddIssueComment-Nobody
May 1, 2014
Project Member #7 blic...@google.com
(No comment was entered for this change.)
Status: Duplicate
Sign in to add a comment

Powered by Google Project Hosting