Live data from Hacker News

How far should a programming language aware diff go?

semanticdiff.com

31–40 of 54 posts

Re: How far should a programming language aware diff go?

#31
post #25

I think I'd appreciate some sort of "semantic grouping" of individual changes more than drawing someone random line and classifying all changes below it as "trivial". The problem is that even a lot of the changes that normally constitute clutter can become relevant in certain situations or even introduce bugs. One example would be ordering of Python imports: Changing the order of imports should have no effect on prog…

I think the problem you'll eventually run into is figuring out intent from the diff. It seems like an easier version of reverse compiling.

When it comes down to semantic diffs I'm more interested in something like the Semantic Patch Language by Coccinelle. Being able to represent mundane refactorings across an entire codebase in a few lines seems great. And it unifies intent with the diff.

Re: How far should a programming language aware diff go?

#32
post #25

I think I'd appreciate some sort of "semantic grouping" of individual changes more than drawing someone random line and classifying all changes below it as "trivial". The problem is that even a lot of the changes that normally constitute clutter can become relevant in certain situations or even introduce bugs. One example would be ordering of Python imports: Changing the order of imports should have no effect on prog…

Agreed, I don't think the value of a semantic diff would be in hiding changes. Instead, the value should be in generating more useful diffs.

Normal diff often gets "confused" compared to how you'd logically identify the code. For example, if you extract a piece of a larger function as a smaller function, instead of showing that a piece of code was moved, it will show that you changed a header, deleted some lines, added others below, etc. A semantic diff should be able to refine these diffs in a better way, but shouldn't hide them. Even for the whitespace changes, I'd like it to show the diff, but the overlay to explain that only whitespace is different, so I know I don't need to look at it carefully.

Re: How far should a programming language aware diff go?

#33
I haven't actually checked the source, but I've heard that clang-format works by assigning "badness" weights to each choice of whitespace between tokens, and then runs Dijkstra's (or some other DP) to find the least bad set of choices. A recent Tom7 video said that Knuth did the same thing for text justification.

How about we do a similar thing for ASTs? Like a peephole optimizer looking for runs of instructions that could be substituted for simpler alternatives, a tree diff could identify diff patterns that "might be trivial." You have a whole catalog of these patterns, and assign to each a weight. Then the displayed diff is the optimal set of choices "consider different or not?"

You would need some additional ingredient, though; some boundary condition. Otherwise "everything is the same" would always minimize badness.

Re: How far should a programming language aware diff go?

#34
Not far. Just show all changes. Like the blog article already states, for many projects you already have code formatters, so changes in format usually don’t happen a lot - and if they do there might be a reason you don’t want to hide (like… you change your rules of code formatting). For all the other example I neither see the point why you would want to hide it. If you don’t want to see commas added in a list, make it a rule that the comma always has to be appended after the last element. Most languages allow that. Semantic equivalence? The JS example isn’t even equivalent because „this“ may have a different context. I’d prefer to have a „dumb“ diff that simply shows all the changes instead of adding these kind of complexities. Just keep your MRs small and there’s no real issue.

Re: How far should a programming language aware diff go?

#35
post #9

Earlier quoted context omitted.

More specifically, the `function` keyword version of an anonymous function preserves the keyword `this` whilst the arrow syntax anonymous function does not. Arrow functions also cannot use the `yield` keyword nor be used as constructors https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

There is also the function scope vs block scope... var x = 3 will escape the latter.

If you mean the following, it actually doesn't:

  (function () {
    var x = 0;
    const foo1 = function(a, b) { var x = 2; }
    const foo2 = (a, b) => { var x = 3; }
    foo1(); console.log(x); // prints 0
    foo2(); console.log(x); // prints 0
  })()
However, there is the difference in how the implicit semicolons are inserted:

  const foo1 = function(a, b) { return a + b; }
  (2, 3)
  console.log(foo1) // prints 5

  const foo2 = (a, b) => { return a + b; }
  (2, 3)
  console.log(foo2) // prints [Function: foo2]

Re: How far should a programming language aware diff go?

#36
post #5

> - const foo = function(a, b) { ... } > + const foo = (a, b) => { ... } Assuming this is JS code, these differences should not be ignored, as an arrow function can behave differently than a traditional function.

Yeah I came to say that these are not semantically equivalent (I guess you _could_ verify equivalence if you ensured it did not use this or eval)

Re: How far should a programming language aware diff go?

#38
post #35

Earlier quoted context omitted.

There is also the function scope vs block scope... var x = 3 will escape the latter.

If you mean the following, it actually doesn't: (function () { var x = 0; const foo1 = function(a, b) { var x = 2; } const foo2 = (a, b) => { var x = 3; } foo1(); console.log(x); // prints 0 foo2(); console.log(x); // prints 0 })() However, there is the difference in how the implicit semicolons are inserted: const foo1 = function(a, b) { return a + b; } (2, 3) console.log(foo1) // prints 5 const foo2 = (a, b) => { re…

haha, oh ASI - I was very confused by your example as I read this as if it was

  > const foo1 = function(a, b) { return a + b; }
  (2, 3)
  > console.log(foo1) // prints 5

  > const foo2 = (a, b) => { return a + b; }
  (2, 3)
  > console.log(foo2) // prints [Function: foo]
Even though it makes no sense for (2, 3) to be a result in those cases, that was just how I ended up reading it, and I was exceptionally confused about how the printed output could possibly happen.

A super nice example of how subtle differences can really change things though.

As a side note, ASI for JS is actually super easy to implement and the rules are actually really simple (leaving aside whether the feature itself is good :D ) as it's just "these specific statements can have a new line instead of a semicolon" - so in the parser instead of consume(semicolon) you can just do "semicolon or newline" (You can check the logic in JSC in https://github.com/WebKit/WebKit/blob/main/Source/JavaScript... - just look for autoSemicolon() or autoSemi() I can't recall off the top of my head)

Re: How far should a programming language aware diff go?

#39
post #25

I think I'd appreciate some sort of "semantic grouping" of individual changes more than drawing someone random line and classifying all changes below it as "trivial". The problem is that even a lot of the changes that normally constitute clutter can become relevant in certain situations or even introduce bugs. One example would be ordering of Python imports: Changing the order of imports should have no effect on prog…

I think the problem you'll eventually run into is figuring out intent from the diff. It seems like an easier version of reverse compiling. When it comes down to semantic diffs I'm more interested in something like the Semantic Patch Language by Coccinelle. Being able to represent mundane refactorings across an entire codebase in a few lines seems great. And it unifies intent with the diff.

And just like that, another GPT-4 wrapper startup was born.

Re: How far should a programming language aware diff go?

#40

I haven't actually checked the source, but I've heard that clang-format works by assigning "badness" weights to each choice of whitespace between tokens, and then runs Dijkstra's (or some other DP) to find the least bad set of choices. A recent Tom7 video said that Knuth did the same thing for text justification. How about we do a similar thing for ASTs? Like a peephole optimizer looking for runs of instructions that…

https://en.wikipedia.org/wiki/Edit_distance
Post reply on HN