Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve active pattern errors #1389

Closed
MangelMaxime opened this issue Apr 18, 2018 · 4 comments
Closed

Improve active pattern errors #1389

MangelMaxime opened this issue Apr 18, 2018 · 4 comments

Comments

@MangelMaxime
Copy link
Member

Description

Considering the next code:

type Test =
    | Msg1
    | Msg2

let testToString msg =
    match msg with
    | Msg1 -> "msg 1"

We generate this code:

import { setType } from "fable-core/Symbol";
import _Symbol from "fable-core/Symbol";
import { comparePrimitives } from "fable-core/Util";
export class Test {
  constructor(tag) {
    this.tag = tag | 0;
  }

  [_Symbol.reflection]() {
    return {
      type: "Test.Test",
      interfaces: ["FSharpUnion", "System.IEquatable", "System.IComparable"],
      cases: [["Msg1"], ["Msg2"]]
    };
  }

  Equals(other) {
    return this.tag === other.tag;
  }

  CompareTo(other) {
    return comparePrimitives(this.tag, other.tag);
  }

}
setType("Test.Test", Test);
export function testToString(msg) {
  if (msg.tag === 0) {
    return "msg 1";
  } else {
    throw new Error("test.fs", 7, 10);
  }
}

Proposition

I would like to add a custom Error type to Fable: MatchError (or something like that) and generate something like:

class MatchError extends Error {
  constructor(failingCase, ...params) {
    // Pass remaining arguments (including vendor specific ones) to parent constructor
    super(...params);

    // Maintains proper stack trace for where our error was thrown (only available on V8)
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, CustomError);
    }

    // Custom debugging information
    this.failingCase = failingCase;
  }
}
    throw new MatchError(msg, "test.fs", 7, 10);

Why ?

The idea behind this proposition is to make Elmish errors understandable.

Today we have something like:

capture d ecran 2018-04-18 a 16 59 18

Tomorrow we could have:

Unable to process message:
Msg2

From file: 
Test.fs

Also, if this is a nested DU we get direct access to the whole tree:

type Test =
    | Msg1 of string
    | Msg2 of Test

printfn "%A" (Msg2 (Msg1 "deep_string"))
// Log: Msg2 (Msg1 "deep_string"))

This can be really useful in Elmish application where every message is a nested DU

@alfonsogarciacaro
Copy link
Member

Interesting, I usually just check the warnings that tell me about non-exhaustive pattern matching but it should definitely be possible to have a more informative message for pattern matching errors. We just need to find a way to identify this kind of exceptions.

@MangelMaxime
Copy link
Member Author

I do that in general but when you have several non implement case it's not helping :)

Also, when adding a subcomponent this can help identify which parent didn't update it correctly etc.

Is it fable writting: throw new Error("test.fs", 7, 10); or something coming from the compiler AST ?

@alfonsogarciacaro
Copy link
Member

It's from the F# compiler AST. I guess it's using a particular kind of exception (which we may use to identify it) but Fable is translating it as a general exception at the moment.

@alfonsogarciacaro
Copy link
Member

Fixed by #1611, thanks @Zaid-Ajaj!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants