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

Replace usage of Maps.newHashMapWithExpectedSize() with standard Java #2976

Merged

Conversation

HannesWell
Copy link
Member

In Java-19 there is even static factory method HashMap.newHashMap(int) that can be used as a drop-in replacement once Java-19 or later is required.
For now I calculate the necessary capacity explicitly using the formula: expected-size *4/3+1.

The change in XtextGeneratorTemplates also removes the usage of Maps.newHashMapWithExpectedSize() of many generated Activators, but I haven't changed them manually. I assume they should be regenerated, shouldn't they?

Part of #2975

@LorenzoBettini
Copy link
Contributor

I think @szarnekow should review this, but personally, I'm not a big fan of such strange expressions for computing the size ;)

another note: Maps.of returns an immutable map, IIRC. Could this potentially lead to breakage if the current factory method returns a mutable list?

@HannesWell
Copy link
Member Author

I think @szarnekow should review this, but personally, I'm not a big fan of such strange expressions for computing the size ;)

Is it about the expression or specifying the size at all?

If it is the latter, I can also remove it. If it is the former I'm fine to restrict this PR to the change of XtextGeneratorTemplates.xtend, which is 'required' for eclipse/mwe#287 (comment) or at least the changes that use only constants. I mainly did the others for completeness.
The remaining parts could then be replaced as soon as Java-21 is required using the method HashMap.newHashMap(int) introduced in Java-19 as mentioned in my initial message.

another note: Maps.of returns an immutable map, IIRC. Could this potentially lead to breakage if the current factory method returns a mutable list?

That's right. But I have only used it in two places where the map is passed as userData to EObjectDescription.create(). And if I have followed the code-path correctly that map is only read there.

@HannesWell HannesWell force-pushed the replace-Maps_newHashMapWithExpectedSize branch from 4394639 to 85ca11f Compare April 12, 2024 23:22
@HannesWell HannesWell marked this pull request as ready for review April 12, 2024 23:22
@HannesWell
Copy link
Member Author

I have now reverted the changes that require computation of the capacity. That can be replaced once the Java-19 HashMap.newHashMap(int) is available for Xtext.
The main change for this PR in XtextGeneratorTemplates.xtend is not affected by that.

@HannesWell
Copy link
Member Author

Is there anything left here to land this?

@cdietrich
Copy link
Member

i guess a rebase would be helpful.
and any cappa in the team that does not need to be spent on breaking upstream changes....

@HannesWell HannesWell force-pushed the replace-Maps_newHashMapWithExpectedSize branch from 85ca11f to e911c27 Compare August 8, 2024 21:24
@HannesWell
Copy link
Member Author

i guess a rebase would be helpful.

Rebased it and looked into the currently open issues and answered where I can think I can help something. :)

@@ -48,8 +47,7 @@ protected boolean createEObjectDescriptions(IQualifiedNameProvider qualifiedName
try {
QualifiedName qualifiedName = qualifiedNameProvider.getFullyQualifiedName(eObject);
if (qualifiedName != null) {
Map<String, String> userData = Maps.newHashMapWithExpectedSize(1);
userData.put(NS_URI_INDEX_ENTRY, Boolean.toString(isNsURI));
Map<String, String> userData = Map.of(NS_URI_INDEX_ENTRY, Boolean.toString(isNsURI));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reluctant to accept this change, since the map will now throw an NPE when queried with null as a key. Though that's a valid implementation of the Map interface, it doesn't follow the principle of least surprise, which would just be containsKey(null) == false and get(null) == null

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In both cases the map is passed to org.eclipse.xtext.resource.EObjectDescription and only queried in

@Override
public String getUserData(String name) {
if (userData==null)
return null;
return userData.get(name);
}

The doc of that method already defines that the name argument must not be null:

/**
* Access to specific user data.
* @param key the user data key. May not be <code>null</code>. Unknown keys yield <code>null</code>.
* @return the value. May be <code>null</code>.
*/
String getUserData(String key);

It was indeed not enforced before, but the new behavior would be 100% compliant with the specification of the method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understandable. Yet I prefer some simple guidelines in a code base, one of which would be to avoid the overly strict immutable collections. I've seen to many NPE when doing containsKey, indexOf or contains checks on these with a null in code paths that used to work great until they were refactored to the immutable collections.

Copy link
Member Author

@HannesWell HannesWell Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think it is good that these immutable collections are strict with null elements since one is forced to be more careful in using null, which on the long run and in general is an improvement for a code base, even though it can be annoying in the beginning.

But since you prefer not to use it here I replaced these two usages of Map.of() with HashMap.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious: Why didn't you use Collections.singletonMap instead?
(No need to change this)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious: Why didn't you use Collections.singletonMap instead?

I'm not sure anymore. I think I just forgot it during the discussion and initially I probably assumed that Map.of() is more elegant while meeting the spec. of the methods.

(No need to change this)

Even if there is no need, I think that's the better solution and change it accordingly.

@HannesWell HannesWell force-pushed the replace-Maps_newHashMapWithExpectedSize branch 2 times, most recently from 2d4ab0a to b455f1c Compare August 12, 2024 06:51
Copy link

github-actions bot commented Aug 12, 2024

Test Results

  6 460 files  ±0    6 460 suites  ±0   3h 12m 48s ⏱️ + 6m 42s
 43 240 tests ±0   42 657 ✅ ±0    583 💤 ±0  0 ❌ ±0 
170 100 runs   - 5  167 736 ✅ ±0  2 354 💤 ±0  9 ❌  - 3  1 🔥  - 2 

Results for commit 9ebd37b. ± Comparison against base commit 01fced3.

♻️ This comment has been updated with latest results.

@LorenzoBettini
Copy link
Contributor

@HannesWell two things I don't understand about test results:

  • there's no way to see the actual results? I can't seem to be able to click anything on the results
  • if it works only for PR, then it won't work for committers, since we skip the building for our PRs and only build for pushes

@LorenzoBettini
Copy link
Contributor

Of course, for the second item, we could change our design and also build PRs for committers, cc @cdietrich

@szarnekow
Copy link
Contributor

@LorenzoBettini Does your comment on the other MR mean that the check result Some checks were not successful cannot be trusted?

@LorenzoBettini
Copy link
Contributor

@LorenzoBettini Does your comment on the other MR mean that the check result Some checks were not successful cannot be trusted?

The "Build / Test Results" failing cannot be trusted: it fails even in the presence of flakes. We can only trust "Build / build..." jobs failing.

Unfortunately, the test results action cannot handle flaky tests currently.

@HannesWell HannesWell force-pushed the replace-Maps_newHashMapWithExpectedSize branch from 83ae503 to 9ebd37b Compare August 19, 2024 05:53
@HannesWell
Copy link
Member Author

Can this be considered for Xtext M3?

Copy link
Contributor

@szarnekow szarnekow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be ok with merging für M3

@cdietrich cdietrich merged commit bfa5351 into eclipse:main Aug 19, 2024
8 of 9 checks passed
@HannesWell HannesWell deleted the replace-Maps_newHashMapWithExpectedSize branch August 19, 2024 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants