Hacker News new | ask | show | jobs
by rtpg 3171 days ago
I think there's a lot of useful unexplored territory in this sort of tool. So much work nowadays is happening in maps/dictionaries/what-have-you, with a lot of work being, essentially, data shape transformation.

Despite this, many languages aren't great at this! we have tools that work alright on first-order operations but fall apart on higher level things.

Even really simple things like "conditionally include a key" are rarely supported in a way that leads to concise code. How many times have we all written

  foo = {...}
  if bar:
     foo['a'] = x
instead of something like

   foo = { ... , 'a': x if bar }
and then having bugs because of branches? Tools that solve this sort of problem will be to modern programming what things like the Unix shell was to data mungers in the past.

Haskell lenses kinda goes into this stuff, though Haskell itself is a bit hard to use in a lightweight fashion. Clojure has Specter. But still looking for some more stuff to fill this hole, especially in the "transitionally typed" stuff like Typescript or Python + Mypy

4 comments

IMHO any tool that converts JSON to JSON is pointing to the wrong direction.

Json should strictly be used as a serialization format and everyone who touches it should immediately parse it into a typed data-structure that represents your domain better.

In fact you really should represent your data in your code using whatever native object hierarchy / algebraic data types / option types / etc. your language supports. (Algebraic datatypes are awesome at this sort of thing, it allows you to avoid the aforementioned conditionality)

The problem is the right way to do this is also the hard way, because people hate writing "boilerplate" classes and serialization code and once you start thinking about making it "easy", you end up using json as the in-application data structure because "who needs types anyway".

You are very correct. Boilerplate (de)serialization code is 100x better to have to write than code with JSON-blobs pretending to be business objects.
Since you're using Python for your example, it's worth mentioning that 3.5 extended the unpacking syntax [1] to sort of do what you want.

    foo = {
        'a': 1,
        'b': 2,
        **({
            'c': 3,
            'd': 4,
        } if bar else {}),
    }
This adds `c: 3` and `d: 4` into `foo` conditional on `bar`.

[1] https://docs.python.org/3/whatsnew/3.5.html#pep-448-addition...

oh, this is most definitely a thing I want. Not sure if my coworkers would appreciate this however. Would still have liked a bit of a simpler syntax for inclusion but this could be worth the ugliness

Nice that this works on lists as well.

Yeah, I personally find this sort of syntax convolution ugly and hard to read but I thought it relevant. Enough rope to hang yourself with and whatnot.
> Haskell lenses kinda goes into this stuff

They seem neat but I haven't come across a case where whipping up, in vanilla old-school Haskell, a custom set of small simple ADTs and the related handful of recursing walk-and-transform functions didn't do the job perfectly cleanly and comprehensibly.. this sort of stuff is already very compact to write and code-gen like TH seems almost overkill to me. Guess I'm itching to come upon a much more painful scenario to finally give them "lenses" a fair chance.

If you like writing

    let x = y { foo = foo y { bar = bar (foo y) + 1 } }
instead of

   let x = over (foo.bar) (+1) y
then more power to you!
A neat example indeed! Yeah that makes sense. Especially I guess in code-bases where such deeply-nested record updates abound everywhere repeatedly time-and-again --- have not run into such myself yet. Writing the above on-the-rare-occasion is hardly troublesome. But I get the idea there now. (Although in the above, half the verbosity comes from using records instead of ADTs' ctors and I believe aren't there common idiomatic "standard" GHC lang-extensions to trim record updates in a shorter fashion --- ah well, been a while, I'm dabbling more in PureScript these days which sports a terser record-updates notation anyway =)
It's even worse if you don't have records!

    let x = Y (Foo (old_bar + 1) quux) baz
        where Y (Foo old_bar quux) baz = y
>How many times have we all written

A decent amount, but I'd rather have all of that separate because it makes the code easier to read.

I'm not interested in how concise a block of JSON text can be with all of my transformations of conditionals and loops. That's going to be difficult to read without highlighting. I also can't put a breakpoint in the middle of some JSON text without the appropriate support from the language/runtime/IDE.

However, this syntax is much better than JSON Patch which I've considered using for document templates.

agree that readability is super important.

I think there's a bit of a conflict with regards to immutability. When I see a variable in the code, it's much easier to handle a single definition rather than a "half-definition" followed by a bunch of conditionals.

I've also seen some waaay to concise code that becomes super legible after just one extra line of code to split things up.

I've run into the opposite problem a lot though. Even if every operation is simple, the length of code makes the intent unclear, especially in cases involving aggregation. Death by a thousand cuts

   results = []
   for elt in other_array:
      if elt is None:
         results.append(0)
      else:
         results.append(f(elt))

   
   results = [ f(elt) if elt is not None else 0
               for elt in some_other_array ]
In one example we have to read several lines to figure out some basic stuff, but in the other I can tell even at a quick glance that we have a mapping from one container to another, an expectation they're the same size, etc.

Clarity is the most important, and after a couple conditionals it makes sense to be more explicit about control flow. But many common tasks are not _about_ control flow, even if C-isms make us write them as if they do. "if" statements generate so many bugs, eliminating them is great.