Live data from Hacker News

On the proliferation of try, and soon, await (2020)

forums.swift.org

11–20 of 44 posts

Re: On the proliferation of try, and soon, await (2020)

#12

The original poster says that these functions can't ever have invariants broken: > Functions that only mutate instances of well-encapsulated types through their public APIs. That includes nearly all functions that are not methods. > Methods of well-encapsulated types that only mutate non-member instances of other well-encapsulated types through their public APIs. This is incorrect! Consider the following function (in…

Your premise assumes that `insert` will abort immediately if `get_location` or `compute_metadata` throw, but that's an arbitrary (poor) decision by the author of `insert`. The errors can (should) be caught and the relationship between `locations` and `metadatas` restored in the handler.

And there's certainly no reason for `insert` to re-throw its helpers' internal errors. What would its caller do with them?

Re: On the proliferation of try, and soon, await (2020)

#13

The original poster says that these functions can't ever have invariants broken: > Functions that only mutate instances of well-encapsulated types through their public APIs. That includes nearly all functions that are not methods. > Methods of well-encapsulated types that only mutate non-member instances of other well-encapsulated types through their public APIs. This is incorrect! Consider the following function (in…

BTW thank you for reminding what a pain mutable data are, and doubly so, mutable data that can be put into invalid by merely calling legitimate methods.

Re: On the proliferation of try, and soon, await (2020)

#14

One of the interesting things (IMO) about programming language design is how the designer can choose to make some concepts harder or easier to express, and how those decisions shape the kind of programs that are easy to write with the language. Here, Swift (it seems) makes an implicit suggestion that a developer keep their error handling tight and bounded. If you don't, the language softly penalizes you with the need…

I don't know why but for a moment I read this comment in horror imagining language developers implementing telemetry in the compilers and tooling themselves, then relying on them to "improve the experience" by changing the spec every six months.

Microsoft dotnet has opt-out telemetry. I'm not sure for what.

Re: On the proliferation of try, and soon, await (2020)

#16

One of the interesting things (IMO) about programming language design is how the designer can choose to make some concepts harder or easier to express, and how those decisions shape the kind of programs that are easy to write with the language. Here, Swift (it seems) makes an implicit suggestion that a developer keep their error handling tight and bounded. If you don't, the language softly penalizes you with the need…

What do you think of Java's declared exceptions (or whatever they're called)? They always seemed like a good idea to me, but were ruined by people being lazy or not understanding how to properly design exceptions.

Re: On the proliferation of try, and soon, await (2020)

#17

One of the interesting things (IMO) about programming language design is how the designer can choose to make some concepts harder or easier to express, and how those decisions shape the kind of programs that are easy to write with the language. Here, Swift (it seems) makes an implicit suggestion that a developer keep their error handling tight and bounded. If you don't, the language softly penalizes you with the need…

What do you think of Java's declared exceptions (or whatever they're called)? They always seemed like a good idea to me, but were ruined by people being lazy or not understanding how to properly design exceptions.

Personal opinion: I think they were a good idea but in practice they don't work great because they try to pretend exceptions work differently from how they really work.

They bump up against a reality of exceptions in a bad way: once you have a system for throwing exceptions, the set of types your code must handle becomes fundamentally unbounded because any of your dependencies can change at any time. If there are no exceptions and you have a function-call control flow, you can enforce that the only types the caller understands from the callee are the types in the signature. If your language supports thrown exceptions, then at the site of a function call, the value resulting from the call can be the values in the signature or any exception that can be generated by any function called by the callee (and in general, without control of the entire code stack, that set is unknowable).

That's a fundamental truth of thrown exceptions, and trying to constrain it by putting the thrown type in the signature left us in the state we're in now... People just throw and catch very abstract exceptions because they'll have to handle those exceptions anyway, since it's impossible to guarantee a dependency won't try to throw them.

Re: On the proliferation of try, and soon, await (2020)

#18

The original poster says that these functions can't ever have invariants broken: > Functions that only mutate instances of well-encapsulated types through their public APIs. That includes nearly all functions that are not methods. > Methods of well-encapsulated types that only mutate non-member instances of other well-encapsulated types through their public APIs. This is incorrect! Consider the following function (in…

Your premise assumes that `insert` will abort immediately if `get_location` or `compute_metadata` throw, but that's an arbitrary (poor) decision by the author of `insert`. The errors can (should) be caught and the relationship between `locations` and `metadatas` restored in the handler. And there's certainly no reason for `insert` to re-throw its helpers' internal errors. What would its caller do with them?

I agree. A function that properly handles its helpers internal errors is better than a function that simply rethrows them. However, both are better than a function that simply rethrows them AND leaves the application in an inconsistent state. Additionally, adding the "try" syntax makes it clear that "insert" has been written poorly. For example, consider the code:

    func insert(id: Int, object: ThingInSpace) {
      var location = try get_location(object);
      ids.update(id);
      locations[id] = location;
      metadatas[id] = compute_metadata(object);
    }
Now I can be sure that compute_metadata doesn't fail, so it's fine that I've inlined the call, whereas it's important that get_location isn't inlined. But this syntax also suggests to a code reviewer that maybe insert should wrap the error returned by get_location and caught.

Of course you could always catch the error and restore the state, but without the `try` syntax, you can't tell by reading the function which lines can fail, and where you need to handle the error.

Re: On the proliferation of try, and soon, await (2020)

#19
post #5

Earlier quoted context omitted.

But you broke encapsulation because locations and metadatas have an invariant that must be externally enforced. I don't think that meets the standard of well-encapsulated. If locations and metadatas must be updated together then you should only be able to do it via some method update() that takes location and metadata.

Consider this to be the only function that modifies locations and metadatas. It is the function that is supposed to maintain that invariant. You can pass in location and metadata (or make this a method on an object with those values as private members) without changing my point. Under the rules laid down by the original poster in the link, functions which only modify well-encapsulated types via their public APIs cann…

> well-encapsulated types via their public APIs cannot violate invariants

… of those well-encapsulated types. Throwing an exception like this cannot break an internal invariant of the list object which is what the author is saying.

You can’t break the list object which sounds crazy by modern standards but in languages without this kind of encapsulation (like C) this can and does happen.

Re: On the proliferation of try, and soon, await (2020)

#20

One of the interesting things (IMO) about programming language design is how the designer can choose to make some concepts harder or easier to express, and how those decisions shape the kind of programs that are easy to write with the language. Here, Swift (it seems) makes an implicit suggestion that a developer keep their error handling tight and bounded. If you don't, the language softly penalizes you with the need…

What do you think of Java's declared exceptions (or whatever they're called)? They always seemed like a good idea to me, but were ruined by people being lazy or not understanding how to properly design exceptions.

With checked exceptions, if today my function can only throw a FileException, then tomorrow I cannot start throwing a URLException without breaking any callers depending on my function having only one possible exception type. The lead architect of C# cited this problem as one of his reasons for not adding checked exception to that language. https://www.artima.com/intv/handcuffs.html#part2

The solution to the problem with to have errors be dynamically typed (a trait in Rust, an interface in Go, etc.) and insist that callers be ready for an unknown error type to bubble up.

Post reply on HN