Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What is the rationale for throwing away semantic information by collapsing blank lines? #12086

Closed
fenomas opened this issue Jan 15, 2022 · 7 comments

Comments

@fenomas
Copy link

fenomas commented Jan 15, 2022

Prettier 2.5.1

Consider code like the following:

Playground link

--parser babel

Input:

class Cat {
  /* ... */
}

class Dog {
  /* ... */
}




class Pizza {
  /* ... */
}

class Hamburger {
  /* ... */
}

In code like that the consecutive blank lines clearly aren't just a style preference, they're a semantic cue to the reader about which classes are closely related, and which aren't.

After Prettier collapses the blank lines, the semantic meaning is lost and all classes appear equally related:

Output:

class Cat {
  /* ... */
}

class Dog {
  /* ... */
}

class Pizza {
  /* ... */
}

class Hamburger {
  /* ... */
}

The difference is obviously trivial in a short empty snippet like this, but in large files containing lots of classes, vertical space becomes a very important, common semantic tool for the developer to convey how the file's contents are separated. (This is especially obvious if you use the "minimap" feature of modern editors - code minimaps can be great for navigating large files, but after prettier strips out all the semantic whitespace the minimap becomes largely useless.)


Even worse, consider the use case of Single File Components for front-end frameworks. A typical SFC file might look like this:

Playground link

--parser vue

Input:

<template>
  <div>
    <div>Some text content</div>

    <div>Some text content</div>

    <div>Some text content</div>
  </div>
</template>



<script>
import { thing } from '../somewhere'

function foo() {
  // ...
}

function bar() {
  // ...
}

export default {
  stuff: {},
}
</script>



<style>
@import url('../blah.css');

.rule1 {
  position: relative;
}

.rule2 {
  position: absolute;
}

.rule3 {
  display: inline-block;
}
</style>

Again, the blank lines are being used semantically - to visually separate source code in unrelated formats.

After prettier is used, the result is much harder to read - the vertical space between, say, JS and CSS is now exactly the same as the separation between two JS functions or two CSS rules. Even though the file is semantically divided into three clearly separate parts, prettier makes it impossible for that separation to be visually apparent.

Output:

<template>
  <div>
    <div>Some text content</div>

    <div>Some text content</div>

    <div>Some text content</div>
  </div>
</template>

<script>
import { thing } from "../somewhere";

function foo() {
  // ...
}

function bar() {
  // ...
}

export default {
  stuff: {},
};
</script>

<style>
@import url("../blah.css");

.rule1 {
  position: relative;
}

.rule2 {
  position: absolute;
}

.rule3 {
  display: inline-block;
}
</style>

Expected behavior:

Shouldn't prettier simply stop collapsing blank lines?

If not, what's the rationale for stripping out semantic information this way?

@sosukesuzuki
Copy link
Member

We have the page on website to describe rational of empty lines formatting. See https://prettier.io/docs/en/rationale.html#empty-lines. Is it an enough answer for your question?

@sosukesuzuki sosukesuzuki added the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Jan 22, 2022
@fenomas
Copy link
Author

fenomas commented Jan 22, 2022

@sosukesuzuki Hi, that page is actually the source of my question. It says that prettier takes the approach of preserving blank lines, but then turns around and says that it doesn't preserve multiple consecutive blank lines. But no rationale is mentioned for why this is done.

My question here is why the latter rule exists - why not preserve consecutive blank lines, and keep the developer's semantic intent?

@no-response no-response bot removed the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Jan 22, 2022
@sosukesuzuki
Copy link
Member

Thanks. I was not involved of this rationale, so I don't know the reasoning behind it. But that's probably because they simply couldn't find a rule that would satisfy more users than the current one. it is heuristics.

@fenomas
Copy link
Author

fenomas commented Jan 22, 2022

Hmmm. I went looking through old issues, and the only discussion I could find was this one. There seemed to be more commenters against the rule than for it.

As I read it, I guess prettier's rationale here was simply that throwing away a little bit of semantic information is okay if it keeps the style consistent? This seems like an very strange policy for a style formatter... 😦

@alexandernanberg
Copy link

Part of the reason why I'm using prettier is that it forces consistent spacing, I feel like if you need to separate things more you can use comments

@fenomas
Copy link
Author

fenomas commented Jan 24, 2022

@alexandernanberg Per the linked docs, prettier specifically doesn't force consistent spacing with newlines. It preserves them as written, with the addition of this rule where it throws away semantic information. It would be better to just preserve them as written.

@thorn0
Copy link
Member

thorn0 commented Sep 8, 2022

Prettier can't tell whether a blank line is intentional ("semantic") or just sloppiness. So as a middle ground, Prettier doesn't dare remove them completely but also tries to keep things tidy. That's the rationale. Use comments as multi-line separators as they're unanimously intentional. Ideally, Prettier shouldn't have used the input formatting for printing blank lines at all, but an algorithmic way of deciding where to insert blank lines is a really tricky problem to solve (see #2068).

@thorn0 thorn0 closed this as completed Sep 8, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants