News for hackers. Stuff that matters.
Re:Map[string]interface{} in Go: a user's manual by nkozyra on Monday July 26, 2021 @04:27PM (#27964998)
Yeah, the formality of embedded structs can lead to some very verbose bloat. And it obviously only works on very reliable payloads.
Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @04:28PM (#27965015)
What's the solution for an unreliable payload? When things aren't where you expect them in a JSON blob with a Python Flask app, your app also just breaks on that input.
Re:Map[string]interface{} in Go: a user's manual by andrewmcwatters on Monday July 26, 2021 @06:20PM (#27966199)
What solution? There is no solution. The web just works that way.

You receive some bytes and you do stuff with them. Any other expectation is a farce.

Is a property missing after serialization? Can you even serialize it? Maybe a different status code returns a different mime type! OK, whatever. That’s not always an error, nor is it remotely “exceptional.”

Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @06:27PM (#27966251)
I mean, I agree. That's why I'm sort of confused about what the problem is here. Yes, you can get unreliable inputs. Most apps barf on them, even if they think they don't. The barfing mechanism is pretty much the same everywhere.
Re:Map[string]interface{} in Go: a user's manual by tgsovlerkhgsel on Monday July 26, 2021 @05:50PM (#27965928)

    try:
      val = input['foo']['bar']
    except KeyError, TypeError:
      raise HttpErrors.BadRequest
Re:Map[string]interface{} in Go: a user's manual by Kocrachon on Monday July 26, 2021 @06:07PM (#27966091)
Can someone explain to me why python uses try/except so often? I see that promoted as a solution instead of;

if 'bar' in input['foo'].keys(): val = input['foo']['bar']

Generally, exceptions cause code to run slower and I feel like in any other language is considered bad practices.

I never understood why Python promotes EAFP vs LBYL. Both performance and accuracy wise, checking before doing is safer and faster performance.

Re:Map[string]interface{} in Go: a user's manual by kortex on Monday July 26, 2021 @07:43PM (#27966915)
Well, firstly input.get("foo", {}).get("bar", default) is a bit nicer, imho.

Python exceptions are only slower on the exception. They are almost exactly the same speed on success.

LBYL forces you to look for all the ways in which you might leap. EAFP lets you handle even unexpected conditions. The classic use case is checking if a condition exists, then doing the thing, except the condition changed between check and run. So you gotta catch anyways.

I've been moving away from this actually and towards a rust-like Result[T, Exception]. I'm using the package called "result". For fastapi api_request -> handler -> some_func_chain -> return response_to_client patterns, if something barfs, you normally get a 422 and useless "Internal server error". It's far simpler imho to map over some Results and then pack the error(s) into a more useful response.

Also testing is just a lot simpler.

https://pypi.org/project/result/

Re:Map[string]interface{} in Go: a user's manual by tgsovlerkhgsel on Monday July 26, 2021 @06:15PM (#27966161)
Your example will throw a KeyError if "input" doesn't contain "foo", and an AttributeError if "foo" is some unexpected data type that doesn't have keys().
Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @06:10PM (#27966124)
You just generated a 502, and spent a bunch of extra lines doing it. The 502 is bad, and if that's all I need to do, I get that almost for free from net/http's panic handler. It sounds like you don't actually have a problem here.
Re:Map[string]interface{} in Go: a user's manual by tgsovlerkhgsel on Monday July 26, 2021 @06:23PM (#27966222)
I kept the example simple, of course I could now customize the error message further (or take some other sensible action). Note that I returned a 400, not a generic 502 here. If I didn't care at all, I wouldn't need any extra lines. Does the panic handler send a response at all, or does it just drop the connection?

Also, in Go, using panic/recover is considered unidiomatic. You can use it like an exception system, but it's not what you're supposed to do.

Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @06:29PM (#27966266)
I'm not suggesting that you would build a custom exception recovery system; I'm pointing out that net/http, which is definitionally idiomatic, already has that recovery mechanism.
Re:Map[string]interface{} in Go: a user's manual by tgsovlerkhgsel on Monday July 26, 2021 @07:01PM (#27966558)
I believe that that recovery mechanism isn't supposed to be routinely triggered just due to bad user input, and that code that does so would be considered defective.
Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @08:36PM (#27967284)
It's doing almost literally the same thing as the Python code upthread. Just, with less code.
Re:Map[string]interface{} in Go: a user's manual by claudiawerner on Monday July 26, 2021 @06:22PM (#27966209)
I think that was more of an example. There are lots of ways to fail gracefully when you don't have the data you want in the dict.
Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @06:28PM (#27966254)
Right, which is why json.Unmarshal returns an error, and why map lookups return an extra `ok` value in Go.
Re:Map[string]interface{} in Go: a user's manual by tgsovlerkhgsel on Monday July 26, 2021 @07:03PM (#27966569)
It would be a lot more than 4 lines in Go though. Either the struct definition, or a lot of `if !ok return error`. Especially once the nesting gets deeper.
Re:Map[string]interface{} in Go: a user's manual by tptacek on Monday July 26, 2021 @07:29PM (#27966797)
I'm pretty sure it would just be an `if err != nil {http.Error(w, err.Error(), 501); return }`.
Re:Map[string]interface{} in Go: a user's manual by tgsovlerkhgsel on Monday July 26, 2021 @11:19PM (#27968251)
one of these for each nesting level.