Nested catch and throw do not seem to work properly

Posted on
  • Hello All,

    The following code is attempting to generate a catched error inside the 'inner' function and rethrow it to the 'outer' function so that it is catched again there.

    Testing it on JSFiddle does produce the 2 Catch inner and outer to happen, it is not the case on Espruino 1v80.

    Am I missing something?

    function outer() {
     try {
       console.log('In outer');
       inner();
       console.log('Out outer');
     } catch(x) {
       console.log('Catch outer');
    }
    }
    
    function inner() {
     try {
       console.log('In inner');
       throw "coucou";
       console.log('Out inner');
     } catch(x) {
       console.log('Catch inner'+x);
       throw x;
    }
    }
    
    >outer();
    In outer
    In inner
    Catch innercoucou
    Out outer
    =undefined
    Uncaught coucou
     at line 8 col 10
       throw x;
              ^
    > 
    

    There are 2 threads on this forum about catch and throw but they did not helped me...

    Thank's for reading.

  • Hmm, I don't think you're doing anything wrong. That looks like a bug to me... For instance this will work:

    function outer() {
     try {
       console.log('In outer');
       inner();
       console.log('Out outer');
     } catch(x) {
       console.log('Catch outer');
     }
    }
    function inner() {
     var caught;
     try {
       console.log('In inner');
       throw "coucou";
       console.log('Out inner');
     } catch(x) {
       console.log('Catch inner'+x);
       caught = x;
     }
     if (caught) throw caught;
    }
    
    outer();
    

    I'll make sure I put that in the bug tracker.

    To be honest I don't think people generally use exceptions much with Espruino, so it probably hasn't come up before.

  • Ok, thanks!
    I was wondering.
    Anyway, I am using "massively" try-catch-throw to speed up some gps related software. Basically, nmea protocol provides figures much more often than text.
    So I use try as a way to make it faster in most cases, which means numbers, handling exceptions, strings, almost at no extra costs.
    Anyway, that's to be added in the list.

  • Not sure I understand? I'd definitely be interested to see some speed figures - I didn't consider exceptions to be faster than 'normal' code.

    I've fixed the problem now anyway - it should be fixed in this build when it's done, so the 1v81 release.

  • 'Faster'... may be due to the fact that with 'logically massive' use of exceptions overall code code size is smaller and with less code to run it is faster. Elimination of if/then/else and returning and distinction of error/exception codes (on top of application codes) slims code to implementaton of the good path and reduces issues handling code to a minimum and only in the (call hierarchy stack/) layer where of interest. @asez73, as a practitioner of exception paradigm you'd like to share your rational.

  • Hi @Gordon and @allObjects
    Yes, it is basically induced by the code size but not just that. By using try { } catch { }, the exceptions, which rarely occur more than 1/1000 of the time, are effectively not taking any time until they occur. By the end I found something like 45 ms reduced to 25 ms with a constant level of exception handling.

    In fact it started with the GPS module and trying to get more than randomly precise altitudes, latitudes and longitudes. So that implied to handle more than the RMC and GGA which provides just not enough figures to have a correct understanding of the GPS receiver position. For instance GPGBS provides the position's errors.
    The fields extracted from all of those GPS sentences where sometimes repeated between different sentences: latitude, longitude, hour, altitude.
    And furthermore some sentences transmission were interrupted by the receiver itself because outdated. Sentences start with a $, should end by a \r\n sequence. However they may be interrupted by an other, eventually valid, sentence and never be actually ended.

    By the end, I added checksum control of sentences and a better sentence delimitation, serial bauds were raised to 115200 too.

    Now, for instance, the lines below takes 0.01681646164 s per line. But those are empty lines with just the time fix.

    Handling:$GPDTM,W84,,0.0,N,0.0,E,0.0,W84­*6F
    Handling:$GPRMC,093733.00,V,,,,,,,270815­,,,N*79
    Handling:$GPVTG,,,,,,,,,N*30
    Handling:$GPGGA,093733.00,,,,,0,00,99.99­,,,,,,*6B
    Handling:$GPGSA,A,1,,,,,,,,,,,,,99.99,99­.99,99.99*30
    Handling:$GPGSV,1,1,01,21,,,38*70
    Handling:$GPGLL,,,,,093733.00,V,N*47
    Handling:$GPGRS,093733.00,1,,,,,,,,,,,,*­43
    Handling:$GPGST,093733.00,0.0000,,,,3750­003,3750003,3750003*58
    Handling:$GPZDA,093733.00,27,08,2015,00,­00*60
    Handling:$GPGBS,093733.00,,,,,,,*62
    Handling:$PUBX,00,093733.00,0000.00000,N­,00000.00000,E,0.000,NF,5303306,3750003,­0.000,0.00,0.000,,99.99,99.99,99.99,0,0,­0*23
    Handling:$PUBX,03,01,21,-,,,38,056*0B
    Uncaught Error handling line
    at line 7 col 11

    throw "Error handling line";
           ^
    

    Handling:$GPDTM,W84,,0.0,N,0.0,E,0.0,W84­*6F
    Handling:$GPRMC,093734.00,V,,,,,,,270815­,,,N*7E
    Handling:$GPVTG,,,,,,,,,N*30
    Handling:$GPGGA,093734.00,,,,,0,00,99.99­,,,,,,*6C
    Handling:$GPGSA,A,1,,,,,,,,,,,,,99.99,99­.99,99.99*30
    Handling:$GPGSV,1,1,02,21,,,37,28,,,28*7­C
    Handling:$GPGLL,,,,,093734.00,V,N*40
    Handling:$GPGRS,093734.00,1,,,,,,,,,,,,*­44
    Handling:$GPGST,093734.00,0.0000,,,,3750­003,3750003,3750003*5F
    Handling:$GPZDA,093734.00,27,08,2015,00,­00*67
    Handling:$GPGBS,093734.00,,,,,,,*65
    Handling:$PUBX,00,093734.00,0000.00000,N­,00000.00000,E,0.000,NF,5303306,3750003,­0.000,0.00,0.000,,99.99,99.99,99.99,0,0,­0*24
    Handling:$PUBX,03,02,21,-,,,37,057,28,-,­,,28,000*1B

    And once the fix is done, since there is more data to be extracted out of the received sentences, you have a mean time per line of 0.02384059895 s. This figure had gone up to 45 ms in the if/then code structure.

    All of those little variations, around normally received sentences, added some split/pop/if code and beeing applied at every line received, could end up to be run 13 times per second.
    So, a time efficient code analysising the received sentences has become a requirement.

    An other optimisation will be to shut ON or OFF some NMEA sequences once thay have provided the desired data and until this data has to be refreshed: date from GPSZDA is such a case.

    function checksum(msg) {
      var cks = 0;
      for (var s in msg) { cks ^= msg.charCodeAt(s); }
      return cks;
    }
    
    // compute the checksum for NMEA sentences and splits it from ','
    function nmea_checksum(sentence) {
      try {
        var nmeadata=sentence.split('$').pop(); // remove leading uncomplete sentences AND the no more usefull leading $
        nmeadata=nmeadata.split('*'); // separate checksum from line
        var cksum = parseInt(nmeadata.pop(),16); // make checksum a number
        nmeadata=nmeadata.pop(); // keep content alone
        var calc_cksum = checksum(nmeadata);
        if (cksum===calc_cksum) return nmeadata.split(',');
        else {
          throw "different checksums "+cksum.toString(16)+" versus "+calc_cksum.toString(16)+" in line "+sentence ;
        }
      } catch(x) {
        throw "Checksum error "+x+' in sentence '+sentence; 
      }
    }
    
    /* How to stop receiving some NMEA messages from Ublox devices
     Turning off GPS NMEA strings on the uBlox modules
     $PUBX,40,msgId,rddc,rus1,rus2,rusb,rspi,­reserved*cs<CR><LF>
      */
    
    function stop_nmea(to_be_stopped, keep_usb) {  // so GLL, ZDA etc...
      var msg="PUBX,40,"+to_be_stopped+",0,0,0,"+(­(keep_usb) ? "1" : "0")+",0,0";
      var cks = checksum(msg);
      msg="$"+msg+"*"+("0"+(cks).toString(16))­.substr(-2).toUpperCase();
      this.serial.print(0xff); // force wake up of the module
      var timeout= setTimeout(function (a,b) { b.serial.println(a); }, 500, msg, this); 
      // send command after half a second to allow for module wakeup
    }
    
    

    Now I still have to figure out a minimal cost to the handling of the reactions of the application to changes in this data stream. I am thinking about using gps.emit('TimeFix') and other event driven approaches like that. It would clearly separate the application from the receivers status and data.

    Definitly, I am not considering any coding approach but for its real results and efficiency. We are using mcus not linux.
    Any advice is welcome.

  • That's great - thanks for all those details - really interesting to know, and to see some code that you've been doing time tests on.

    Are you running with your code as-is, or minified?

    And does everything work for you with the new build?

  • @Gordon, It runs as is on 1v80.280 so far. I will try the new build today.

    I used a timing approach fairly basic as below:

    // chronometer functionnalities
    
    var Chrono = function (heure) {
      this.reset();
      this.createdAt = heure;
    };
    
    Chrono.prototype.reset = function () {
      this.meanTime=0;
      this.nlines=0;
      this.duration=0;
    };
    
    Chrono.prototype.start = function () {
      this.starttime= getTime();
    };
    
    Chrono.prototype.leap = function () {
      this.nlines++;
    };
    
    Chrono.prototype.stop= function () {
      this.duration+=getTime()-this.starttime;­
      this.meanTime=this.duration/this.nlines;­
    };
    
    Chrono.prototype.toString= function(radix) {
    };
    
    var mychrono = new Chrono(getTime());
    
    
    

    mychrono is then called at proper places in the gps loop.

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

Nested catch and throw do not seem to work properly

Posted by Avatar for asez73 @asez73

Actions