4

Why is single-statement 'try' not a thing? Usually I know exactly which function may throw.

Comments
  • 3
    It is in Ruby.

    blah = foo(bar) rescue whew

    blah is whew if foo() throws (or anything else in the expression)
  • 0
    @Root Cool. I really don't get why we must complicate the AST when we could define {stmt;stmt;stmt;stmt} as a statement that executes each internal statement sequentially, and make every control statement expect a single statement as body.
  • 4
    For TS, in regards to type assignment dynamism:

    TS has no pattern matching at present, only type guards for discrimination, the resulting implicit union type would need to be guarded inside of an additional if statement to be processed correctly.

    A structure Anders and gang might cook up would look like this:

    const errorable: T | Error = try someWorkThatCanThrow();

    If pattern matching were a thing, it would be discriminated like this

    const output = errorable switch{
    T => //some t work,
    Error => // some error work
    }

    As it stands though, that has two impacts:

    1. It promotes the error into a local variable
    2. It creates a second variable assignment routine to process the discriminated output in every case. You don't have to do this in normal execution paths that only invoke catch logic when necessary.

    The other semantic to consider here is you would also need to create either a higher order emulating type at the language level to represent Errorable (any | T) with additional logic to symbolically commute the T variable around the any discriminator, OR, you would need to add additional syntax to convey errorable pipe-ability to pattern matching stuctures (const x = try someErroringWork() match...).

    It just doesn't really flow paradigmatically without a lot of sugaring.
  • 0
    so true I have a bunch of empty catches. Worst thing was that linters see them as errors
  • 1
    agree, why is a catch required? an else statement isn't required for an if
  • 0
    @SortOfTested I'm not talking about something like ternaries. I'm talking about this:
  • 0
  • 1
    Sounds like a job for monads.
  • 0
    @homo-lorens
    That's very obtuse. What I wrote had nothing to do with ternaries.
  • 0
    It is a thing in all languages supporting first-class functions:

    resultOrEx = catchEx(fun, arg0, arg1..., argN)

    catchEx is a function taking a function and its arguments and returning the function's result or its thrown exception.
    The implementation of catchEx is trivial.

    P.S.: Might as well have tryCall(fun, args, funOnSuccess, funOnFailure) and use that with lambda-style functions for funOnSuccess and funOnFailure. Also trivial to implement.
  • 0
    @Oktokolo not quite, there's one more assumption needed for what you just wrote - that exceptions are first-class (are values that you can do whatever with). ML's exception system does that for example, but it's not necessary.
  • 0
    @RememberMe
    I would never have expected a language to have catchable exceptions and at the same time not letting you pass them around.
    Do such languages exist?
  • 0
    @Oktokolo no, languages usually have first class exceptions. It's a conscious design choice however and you can certainly make something where such a thing doesn't exist.

    For example, if your throw or raise construct takes some special thing and not any old object of an "exception" type that is defined just like the other types in your language.
  • 0
    @RememberMe
    Yes, not shooting yourself in the foot for no apparant reason may be a design "choice". But i guess, i will just continue ignoring the other alternative...
  • 0
    @Oktokolo not apparent to you doesn't mean it's useless. It's there in many theoretical languages for example whether intentionally or not and it simplifies analysis or proofs because operationally there are fewer things the can happen. A first class exceptions system is something a language designer has to put effort into building, that might not be needed/wanted.

    Also I mainly mentioned it for completeness.
  • 0
    @RememberMe
    I get that an exception system isn't free. But there really is no point in having a crippled one.
    There are plenty of languages which have none and plenty of languages which have the one with passable exceptions (some where they are their own class of type, some where you can throw anytghing as an exception).
    There is a pretty obvious reason for the lack of languages featuring a crippled exception system: Crippled exception systems are just a waste of everyone's time.

    If you want proofs, you most likely don't want exceptions. Result types are a little less convinient - but they work fine and are way more explicit than the common fall-through exception handling anyway.

    And as i said: Yeah, shooting yourself in the foot indeed is a "choice" that exists...
  • 0
    @Oktokolo well sorry to disappoint you, but a middle ground between no exceptions and first class exceptions happens to be useful.

    I use a mechanism very similar to that (isomorphic, really) for modelling transitions that can't be done easily via usual value semantics but are too simple to warrant the effort of a full first class system. I could extend our framework to support first class exceptions but it's wasted effort, the "reduced" system does pretty much what we need already.

    Granted, this isn't exactly mainstream and you'd almost never do this in a "production" language, but I never claimed otherwise. And it's a genuine use case nonetheless and I don't think I'm shooting myself in the foot deliberately here.
  • 0
    @RememberMe
    Yeah, obviously you don't think that - yet... :P
  • 2
    @SortOfTested In my mind this was just a minor syntactic modification because I find that I write single-statement try blocks a lot. Representing errors by a type union is great, but being completely oblivious to the type of the error object is the problem to solve here, not somehow navigating around a type union with any. In reality I usually know exactly what the code can throw because throws don't happen by themselves, especially in Javascript.
  • 1
    @homo-lorens
    The example you gave swallows the exception after eating its cost. Swallowing exceptions blinds you to the underlying errors, after eating their realization cost. If you catch an exception you should do something with it, or let it bubble to something that will. By extension, returning an exception from a function is catching it in case something else might know what to do with it. That is most of checked exceptions. JS eschewed this paradigm when it adopted Promise, which provides a success/failure railway for async processes.

    A better solution for you would be the Either monad.

    Either way, the change you want will never happen in Typescript because Anders is the largest opponent to that practice, and Rauschmayer agrees. Anders conveys the cost of exceptions in his interviews on C# arch decisions, and it's part of the code standard. TS inherited most of those genetics, and their cumulative knowledge from 50+ sum years in language design.
Add Comment