Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
8000 feat: add boolset linter by arturmelanchyk · Pull Request #6096 · golangci/golangci-lint · GitHub
Nothing Special   »   [go: up one dir, main page]

Skip to content

Conversation

arturmelanchyk
Copy link
@arturmelanchyk arturmelanchyk commented Sep 21, 2025

The PR adds support for boolset linter

boolset is a Go linter that finds map[T]bool values which are effectively used as sets and recommends switching to
map[T]struct{}.
The replacement avoids storing redundant boolean payloads and can cut memory usage for large maps in half while keeping semantics identical.

Signed-off-by: Artur Melanchyk <13834276+arturmelanchyk@users.noreply.github.com>
Copy link
boring-cyborg bot commented Sep 21, 2025

Hey, thank you for opening your first Pull Request !

@CLAassistant
Copy link
CLAassistant commented Sep 21, 2025

CLA assistant check
All committers have signed the CLA.

@ldez ldez added the linter: new Support new linter label Sep 21, 2025
@ldez ldez self-requested a review September 21, 2025 21:18
@ldez ldez changed the title feat: boolset linter feat: ad boolset linter Sep 21, 2025
@ldez ldez changed the title feat: ad boolset linter feat: add boolset linter Sep 21, 2025
@ldez ldez added the waiting for: contributor feedback Requires additional feedback label Sep 21, 2025
@ldez
Copy link
Member
ldez commented Sep 21, 2025

I think that boolmap could be a better name than boolset. There is no notion of Set in Go.

IMHO, this is an "early optimization" linter: there is no problem of using map[]bool, even the Go team uses them inside Go.
It may be an improvement, but always applying this rule is a bad practice, because in most cases, readability is more important than possible optimisations in edge cases with a big map.
I, personally, will never use it.

For now, I don't know if this linter will be accepted; I need to think about it.

@arturmelanchyk
Copy link
Author

Hi @ldez, I appreciate your feedback.



In Golang there isn't a built-in set container type. Sets are just maps but don't care about element values. In Go, map[Tkey]struct{} is often used as a set type. Many Go devs prefer map[T]struct{} for sets because it



- uses zero-size values,



- encodes intent (“presence only”) instead of a tri-state (true/false/absent)
,



- can shave a bit of memory/CPU in large sets




In my opinion the only justified case to use map[T]bool is when we use both true AND false values in it. For example in this case we do want to have false value and we use it as a cache.

	workDone := make(map[string]bool)
	for _, item := range workItems {
		// can be both true and false
		workDone[item] = DoSomeWork()
	}

	for _, item := range workItems {
		if workDone[item] {
			// value successfully processed earlier
		} else {
			// calculation failed but we do not wat to recalculate
		}
	}

However this is quite rare case and my linter will not complain about such use cases.

The suggested linter warns only about usages where map is used as a set with true values only.







My motivation to add this linter is that I found many projects on the internet actually prefer this notation, see my merged PRs to Bbolt, dolt and Xray-core.






At some point I realized that having a linter for this type of issues would make greater impact than just manually fixing them.







As to the naming, boolset actually says what it does: "bool map which is effectively used as a set"

@bombsimon
Copy link
Member

I think the boolset name is fine since it is more or less representing a set. I interpret the name as something like "don't use bool, it's a set".

I agree this is a small optimization in most cases, but I also think a lot of developers aren't aware of ZST (one could say this is as close as we get in Go) and simply avoid this pattern because they're unaware of it.

This is something I use personally even for small collections just to make it clear it's a set and not a map I want to represent, a complement to good variable naming without having to put the type in the variable name. So even though the readme mentions memory and performance, I think this might be just as valid as a code style linter.

I do realize a lot of users wants to roll their own implementation and avoid dependencies, I wonder if encouraging something like deckarep/golang-set to even better represent a set would be a good/better idea.

@arturmelanchyk
Copy link
Author
arturmelanchyk commented Sep 22, 2025

as an example, here is collections.Set type that typescript team uses specifically to avoid invalid map[T]bool usages
https://github.com/microsoft/typescript-go/blob/1ca5a2d97b0c2b93cfc32137c8922185b4f41df0/internal/collections/set.go#L6

IMHO linter should just highlight the issue and not suggest using specific implementations

@ldez
Copy link
Member
ldez commented Sep 22, 2025







My motivation to add this linter is that I found many projects on the internet actually prefer this notation

This is an over-interpretation of your PRs:

  1. There are no expressions of preference inside the reviews.
  2. Some maintainers, inside those PRs, say the same thing as I about "early optimization".

I have a problem evaluating this linter as a "style" linter because, like prealloc, it will be used as a performance requirement instead of something that should be evaluated on a case-by-case basis.
In most cases, this impacts the readability and doesn't provide any improvement.

I have already closed several PRs on my various projects related to preallocating slices or maps in unnecessary cases or on other types of "early optimizations".

I still need to think about this linter.


I do realize a lot of users wants to roll their own implementation and avoid dependencies, I wonder if encouraging something like deckarep/golang-set to even better represent a set would be a good/better idea.

IMHO linter should just highlight the issue and not suggest using specific implementations

I agree that a linter should not recommend a lib, and this lib specifically should be avoided because of the dependency on the mongo-driver.

@ldez
Copy link
Member
ldez commented Sep 22, 2025

This linter is at the borderline between a detector and a linter.

Based on my analysis of several projects, this linter has false negatives (ex: map[string]map[string]bool).
And, once again, in most cases (more than 90%, based on my analysis), the reports can be evaluated as false positives (no huge maps, no concrete performance impact).
This moves the balance to the detector side.

I don't want to reproduce the prealloc situation.

No decision for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

linter: new Support new linter waiting for: contributor feedback Requires additional feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

0