Big update to prettier-extension-monkeyc

I've posted about prettier-extension-monkeyc before, but I've added a bunch of new features that developers will probably like (well, I've been missing them, so maybe you have too).

The new features it implements for VSCode include:

  • Goto Definition. Point at a symbol, Ctrl/Cmd click, and it will take you to the definition. Or F12
  • Goto References. Right click on a symbol and select "Goto References". It will show you all the references. Or Shift-F12
  • Peek Definition/Peek References. Same as above, but in a popup window so you don't lose your place in the original document.
  • Rename Symbol. Right click on a local, function, class or module name, and select "Rename Symbol". It will rename all the references. It doesn't yet work for class members/methods.
  • Goto Symbol. Type Ctrl/Cmd-Shift-O and pick a symbol from the drop down (which has a hierarchical view of all symbols in the current file). This also appears as an outline across the top of the file.
  • Open Symbol By Name. Type Ctrl/Cmd-T, then start typing letters from a symbol name. A drop down will be populated with all matching symbols from anywhere in your project.

Older features include a prettier based formatter for monkeyc, and a monkeyc optimizer that will build/run/export an optimized version of your project.

[edit: My last couple of replies seem to have just disappeared, and the whole conversation seems to be in a jumbled order, so tldr: there's a new test-release at https://github.com/markw65/prettier-extension-monkeyc/releases/tag/v2.0.9 which seems to work for me on linux. I'll do more verification tomorrow, and push a proper update to the vscode store once I'm sure everything is working]

  • This isn't so much a bug, as expected behavior. Garmin's compiler always trusts casts, even when it can prove they're incorrect.

    I mentioned the issue here a long time ago, but don't expect any change.

  • I think it's better to fix this with the trustFeclaredTypes enabled

    Yes, I definitely want a fix that works with trustDeclaredTypes enabled. But I also want it to work when its disabled!

  • "After all, you must have inserted the cast for a reason..."

    Hmmm, maybe not? I see it compiles with: 

    const HR_ZONES_MOCK = null;
    because anywhere I use it accepts null. So maybe this will fix it for me? Though It won't help you in the general case probably. Can't you do what probably most compilers do: treat null different? When you have null it shouldn't matter what the type is. It's not that const X = null as Number?; is different from const X = null; or even const X = null as Float. It's just null. Why do you need to try to guess it's supposed type? It's type is Null, not Number?, but a variable or a function parameter types as Number? (or actually Number or Null) can get a Null so it's OK. And Number can't so it should fail. But all this is not really not important, because all you need to know about it is that it's null. null should propagate the same way as any other type. Or call it Null :) Maybe I shouldn't mix null value with Null type. At the point when you get to:
    if (FOO && BAR != null) then all you need to know if it's null or not, and since Null is the only type it will propagate there, and null is the only value a variable/const with type Null an have you know it's null. If it was a Boolean you would have a 50% chance to guess it right, but with a Null you know 100% that it's null.
    I don't understand what you mean when you say "Garmin's typechecker fails"? I only compile with -l 3 and all the previous version (null as Array<Number>, null as Array<Number>?, null) work without a warning.
  • So basically the problem I'm having is that I want to ignore casts that I know are false; but that might mean that Garmin's type checker falls over later. After all, you must have inserted the cast for a reason.

    So I think maybe I've been confused here. What I wrote definitely applies to

    const X = null as Array<Number>;

    where the cast and the value being cast have nothing in common. If I drop the cast, code that previously type checked will fail to do so. So I will continue to not optimize that case. But I'm pretty sure that

    const X = null as Array<Number>?;

    can just drop the cast. I've been thinking I can't do that because of Garmin's type checker. But anywhere you can write (x as Array<Number>?) and not get an error, you should *also* be able to write null and not get an error.

    But in that case, you don't really need the cast at all, do you?

  • Hmmm, maybe not? I see it compiles with: 

    Ah - I just came to the same conclusion. see below (or maybe above)

  • so which code is safer/better?

    (:typecheck(false))
    function getConfigNumber(key as PropertyKeyType, defaultValue as Number) as Number {
      var value = getConfig(key);
      // other code..
      return value != null ? value : defaultValue;
    }
    function getConfigNumber(key as PropertyKeyType, defaultValue as Number) as Number {
      var value = getConfig(key);
      // other code..
      return value != null ? value as Number : defaultValue;
    }
    I would think the 2nd, because it doesn't disable typecheck for the whole function.
  • exactly, so I removed the cast from the const, and it works.

  • v2.0.40 is out.

    Mostly just fixes for the regressions reported by , and a couple of other issues.

  • so which code is safer/better?

    Definitely the second. But because Garmin doesn't warn when the cast is invalid, the second one isn't as safe as it could be. I only use :typecheck(false) when there's no other way around the problem; or the only way around the problem involves adding otherwise unnecessary code (but the latter is pretty unusual).

    My optimizer now has warnings when eg value is known to not be a Number, which should make such casts a little safer.

  • I don't understand what you mean when you say "Garmin's typechecker fails"

    I was initially assuming your code was like:

    const HR_ZONES_MOCK = null as Array<Number>;
    
    function foo(x as Array<Number>) as Void { ... }
    
    function bar() {
      if (HR_ZONES_MOCK != null && whatever) {
        foo(HR_ZONES_MOCK);
      }
    }
    because that explains why you needed the cast in the first place.
    If I propagate "null" this particular example just about works, because the body of the if is eliminated. But an unguarded foo(null) would fail Garmin's type checker - even though the unguarded call would be fine without my optimizer. *thats* the issue I was trying to deal with. But it *only* applies when you're doing an "illegal" cast. And in those cases, I'll just not bother optimizing.