• Tue 2018.09.25

    I am breaking up my now too large code file into smaller size class objects, leaving out un-necessary develop time functions. The user will add additional functionality by attaching functions.

    https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Classes/extend­s

    When I attempt to use either the 'extends' or 'super' keyword

    >Uncaught TypeError: Can't extend undefined
     at line 3 col 134
    ...jscomp.setPrototypeOf;c(a,b)}else for(c in b)if("prototype"!...
                                  ^
    in function "inherits" called from line 4 col 168
    ...omp.inherits(Square,Polygon);$jscomp.­global.Object.definePro...
                                  ^
    

    Note that I never specified an 'inherits' function.

    Is there support for both keywords?



    EDIT Wed 2018.09.26

    After many more divide and conquer attempts found that:
    The answer is yes. Here is an example where a line of code produces an unexpected and unusual error. How good are your debug skills? See if you can spot it!
    See the function definitions from the MDN docs. Despite this isn't detected as a syntax error, the run-time error occurs.


    1 Attachment

  • I'm not sure I understand? Are you running with a minifier turned on? The code you posted below has no mention of setPrototypeOf or $jscomp.global.Object so I presume they are being added by something.

    Uploading the code in your attached file from the main IDE window:

    class Polygon {
      // ..and an (optional) custom class constructor. If one is
      // not supplied, a default constructor is used instead:
      // constructor() { }
      constructor(height, width) {
        this.name = 'Polygon';
        this.height = height;
        this.width = width;
      }
    }
    
    
    
    
    class Square extends Polygon {
      constructor(length) {
        // Here, it calls the parent class' constructor with lengths
        // provided for the Polygon's width and height
        super(length, length);
        // Note: In derived classes, super() must be called before you
        // can use 'this'. Leaving this out will cause a reference error.
        this.name = 'Square';
      }
    
      get area() {
        return this.height * this.width;
      }
    }
    
    
    var pol = new Polygon( 4, 3 );
    

    works perfectly for me on a recent build of Espruino.

  • Wed 2018.09.26

    I'm surprised and disappointed @Gordon that you missed that one. In your code, instance is of base class and not the derived class. It does however show that syntax checking is working. I left in the commented out instantiation lines that followed to show the difference between the two, valid syntax vs run-time, without the need of submitting two files. Was it necessary to add the obvious comment to un-comment the subsequent lines?

    re: 'The code you posted below has no mention of setPrototypeOf'

    Yes, agreed, and as I mentioned that 'never specified an 'inherits' function' also, so that puzzled me too.

    Per your suggestion, when I checked, I had 'Closure Simple Optimizations' turned on, so your presumption is proved. But, that brings up another issue, does this mean the minification process is bad?

    I turned off minification and code passes fine, but fails when turned on. And even more puzzling, when I pass the source through

    https://closure-compiler.appspot.com

    // ==ClosureCompiler==
    // @output_file_name default.js
    // @compilation_level SIMPLE_OPTIMIZATIONS
    // @formatting pretty_print
    // ==/ClosureCompiler==

    that source compiles with:

    Compilation was a success!

    Sending that code, default.js, to the device results in the same error as in #1. How does one troubleshoot that type of error? If I understand this correctly, converting the minified code to byte code is where the issue lies.


    1 Attachment

  • Uploaded defaultExtends20180926.jsf is generated w/ // @language_out ecmascript5 (ES5) option. Xyz-fillers - either provided as libraries or inline generated - makes it possible to use the ES6 features class, constructor, etc., that's where these $ methods come from. (Trying to compile w/o ES5 output option fails / complains about the get area(....)

    JSC_CANNOT_CONVERT: This code cannot be converted from ES6. ES5 getters/setters (consider using --language_out=ES5) at line 14 character 6
      get area() {
          ^
    

    Interesting are also the stats:

    Original Size:	187 bytes gzipped (321 bytes uncompressed)
    Compiled Size:	710 bytes gzipped (1.77KB uncompressed)
    

    Instead of 'optimization' the opposite happens by a fatty -279.68% to -463.55% (g- and un-zipped).

    Espruino has (some) ES6 native support... and the support is growing, so no need for using ES5 output generation - the ES6 native support for class and constructor saves a lot.

    Espruiono works off of source code, so there is no bytecode generation involved. Espruino though has an option to speed interpretation from source code up by tokenizing before uploading.

    Even though closure-compiler is called blabla-compiler, it is - strictly looked at - more a transpilation... one form of javascript into another (less powerfull) one and - most often - using some poly-filler js library/libraries.

    Initially, Espruino was completely dependent on google's closure compiler, but it had it's issues on different levels:

    • too many uploads of modules (from the sandbox or elsewhere) - and code in the IDE w/ minimizer (closure compiler) w/ optimization on rendered too many calls to the free service - happened to me when doing intense development on multiple modules and application using those. So I started to use the compiler service once and store then the minified code in my local sandbox.

    • needs to follow absolutely the language definition - either es3, 5 or 6. Since Espruino is not fully ES6 it does not guarantee that compiled code does work, even though non-ES6 constructs are used, but compiler know to compile them into more modern, efficient ES6 code or to mix it with ES6 code to make it better.

    For this reasons - and to support Espruino independent and very concisely - @Gordon established the Espruino services in addition to the module services.

    Your experience using the google closure compiler service and ending up w/ code not running on Espruino makes me a bit jittery, because I have an extended set of very small, but tightly dependent modules that I developed this way. I may have to go thru a re-minify to get them all working for current and future Espruino versions. May be I got lucky because they were built with an 8-grader English - I mean JS 1.3 mind, even predating ES5, and would not be that susceptive to that issue.

  • I'm surprised and disappointed @Gordon that you missed that one.

    You gave me code that you tell me isn't working, and I ran it and it works. As it happens on the first line I said "Are you running with a minifier turned on?" which is exactly what the issue is.

    You commonly upload huge files with massive areas of commented code, so I just assumed it was much the same. I'm trying to help you out here - it's not my job to try and decode the mangled bits of code you post up.

    But just to be clear:

    var sq = new Square( 4 );
    

    Works perfectly on cutting edge Espruino builds.

    var res = sq.area();
    

    Doesn't work, because as I have explained before in answer to one of your other questions, you're using a getter. In that case sq.area is good enough to access the value.

    If you get errors running code, can you please just run it on the JS interpreter in your browser first to make sure you're actually writing valid JS?

    But in this case, your errors seem to be because the Closure minifier has converted your code into the following:

    var $jscomp=$jscomp||{};$jscomp.scope={};$js­comp.getGlobal=function(a){return"undefi­ned"!=typeof window&&window===a?a:"undefined"!=typeof­ global&&null!=global?global:a};$jscomp.g­lobal=$jscomp.getGlobal(this);$jscomp.AS­SUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP­=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jsc­omp.objectCreate=$jscomp.ASSUME_ES5||"fu­nction"==typeof Object.create?Object.create:function(a){­var b=function(){};b.prototype=a;return new b};
    $jscomp.underscoreProtoCanBeSet=function­(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(c){}return!1};$j­scomp.setPrototypeOf="function"==typeof Object.setPrototypeOf?Object.setPrototyp­eOf:$jscomp.underscoreProtoCanBeSet()?fu­nction(a,b){a.__proto__=b;if(a.__proto__­!==b)throw new TypeError(a+" is not extensible");return a}:null;
    $jscomp.inherits=function(a,b){a.prototy­pe=$jscomp.objectCreate(b.prototype);a.p­rototype.constructor=a;if($jscomp.setPro­totypeOf){var c=$jscomp.setPrototypeOf;c(a,b)}else for(c in b)if("prototype"!=c)if(Object.defineProp­erties){var d=Object.getOwnPropertyDescriptor(b,c);d­&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.superClass_=b.prototype};var­ Polygon=function(a,b){this.name="Polygon­";this.height=a;this.width=b},Square=fun­ction(a){Polygon.call(this,a,a);this.nam­e="Square"};
    $jscomp.inherits(Square,Polygon);$jscomp­.global.Object.defineProperties(Square.p­rototype,{area:{configurable:!0,enumerab­le:!0,get:function(){return this.height*this.width}}});var pol=new Polygon(4,3),sq=new Square(4);
    

    Which obviously doesn't resemble your original classes much. We can't easily set the compiler up such that it uses some ES6 features but not others, so it tries to convert your ES6 code to ES5.

    As it happens this code actually hit what looks like a bug in Object.setPrototypeOf which I have now fixed, so your code should actually upload correctly. However it looks like if you're planning on using Classes inside modules then for now you're best off with whitespace-only optimisations.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Use of 'extends' keyword in class definition - is it supported?

Posted by Avatar for Robin @Robin

Actions