Tarmil / FSharp.Data.LiteralProviders

F# Type providers generating literals from the compile-time environment
MIT License
135 stars 6 forks source link

Should we emit a dummy Output when a command fails to execute? #20

Open Tarmil opened 2 years ago

Tarmil commented 2 years ago

Currently it's impossible to do something like this because one of the Execs will always fail:

let [<Literal>] IsUnix = String.EQ<Env.OS.Value, "Unix">.Value

// Dumb example of a command that needs to be different on Windows or Unix.
let [<Literal>] FileListing =
    String.IF<IsUnix,
        const Exec<"ls", "-la">.Output,
        const Exec<"cmd", "/c dir">.Output>.Value

Emitting a dummy Output property when the command fails to execute would make the above possible. But it may make the cause of an error harder to find in other unintended cases.

Some options I'm considering:

  1. Always emit Output, with a null or empty value if the command failed to run.
  2. Add a new parameter eg NullOnFailure = true that decides whether to emit a null Output if the command failed to run (false by default).
  3. Always emit Output, and when the command fails to run, its value is the exception message.

I'm leaning towards option 2: it makes the above example more verbose, but the basic use case remains as safe as today.

olivercoad commented 2 years ago

Also leaning towards option 2, as you could actually differentiate between failing to run the command or timeout and a non-zero exit code. Just checking, would it do the same for Error?

Another option could be to add a TryExec and return a result (FSharp.Core.Result). You'd have to match on it at runtime to get the value, but it's more explicit and would also allow you to actually use the exception message if you wanted to for whatever reason.

Tarmil commented 2 years ago

Just checking, would it do the same for Error?

Presumably yeah.

Another option could be to add a TryExec and return a result (FSharp.Core.Result). You'd have to match on it at runtime to get the value, but it's more explicit and would also allow you to actually use the exception message if you wanted to for whatever reason.

That could be useful, although it wouldn't be a "Literal" Provider anymore so it limits the use cases (can't pass it to another TP or an attribute).