Uh oh!
There was an error while loading. Please reload this page.
Implement analyzer for cars-assemble concept exercise - #277
Implement analyzer for cars-assemble concept exercise#277chiarazarrella wants to merge 1 commit into
analyzer for cars-assemble concept exercise#277Conversation
IsaacG
commented
Jun 7, 2025
+cc the @exercism/java maintainers |
| output.addComment(new ReuseCode(WORKING_ITEMS_PER_MINUTE_METHOD, PRODUCTION_RATE_PER_HOUR_METHOD)); | ||
| } | ||
| if(useMagicNumber(n)){ |
There was a problem hiding this comment.
This method seems to check if the number 221 appears anywhere, but the comment in the design.md seems to suggest that it should check if the number appears more than once in the code:
If the solution is repeatedly hard-coding the value 221, inform the student that they could store this value in a field to make the code easier to maintain.
An alternate solution may to set it to a final variable (within a method), especially if it isn't used anywhere else. If the value appears only once, I think that could be fine.
There was a problem hiding this comment.
What if the value appears only once, but there is no final variable declared within the method?
I think this is still a "magic number" and therefore incorrect. Because we do not understand what is the meaning of 221 solely.
Something like:
publicdoubleproductionRatePerHour(intspeed) {
return221 * speed * successRate(speed);
}There was a problem hiding this comment.
The current version correctly flags magic numbers. Since this method (useMagicNumber(MethodDeclaration n)) analyzes only a single MethodDeclaration, which represents one method and not the entire CompilationUnit, any occurrence of the number within that method is rightly flagged as a magic number. Therefore, no change is needed!
There was a problem hiding this comment.
Are you saying that this is still magic?
publicdoubleproductionRatePerHour(intspeed) {
intcars_per_hour = 221;
returncars_per_hour * speed * successRate(speed);
}There was a problem hiding this comment.
Makes sense! Apologies, I completely missed this angle. Indeed, this is not a magic number situation!
There was a problem hiding this comment.
What do you think of something like this?
privatebooleanuseMagicNumber(CompilationUnitnode) {
List<VariableDeclarator> declarations = node.findAll(VariableDeclarator.class);
longdeclarationCount = declarations.stream()
.filter(vd -> vd.getInitializer().isPresent()
&& vd.getInitializer().get().toString().equals(MAGIC_NUMBER))
.count();
longliteralUsages = node.findAll(IntegerLiteralExpr.class).stream()
.filter(lit -> lit.asString().equals(MAGIC_NUMBER))
.count();
returndeclarationCount == 1 && literalUsages == 1;
}There was a problem hiding this comment.
I'm not familiar with how the java analyzer works. I read this as saying, for some node in the AST, if the magic number appears it must be part of a variable declaration. Is that right?
There was a problem hiding this comment.
Yes, and it should be declared only once, with the number not used anywhere else except in that declaration! Right, @kahgoh?
Thanks for catching the above, though!
There was a problem hiding this comment.
Yes, and it should be declared only once, with the number not used anywhere else except in that declaration! Right, @kahgoh?
Uh ... if I go back to what was written in the design.md, it would be no, I don't think that's quite right. The design.md doesn't mention anything about magic number at all - just that the number 221 shouldn't appear in the code more than once in the code.
To be honest, I thought this solution looked ok (assuming this is the only place where 221 appears):
publicdoubleproductionRatePerHour(intspeed) {
return221 * speed * successRate(speed);
}If 221 should only be in the declaration, what about the other numbers? The reference solution shows there are also other numbers in the solution like 10, 9, 5, 0.77, etc.
| BlockStmt stmt = n.getBody().get(); | ||
| List<Statement> IfStmts = stmt.getStatements().stream().filter(Statement::isIfStmt).toList(); | ||
| for(Statement s : IfStmts){ | ||
| return ((IfStmt) s).hasElseBlock(); |
There was a problem hiding this comment.
Something here seems strange here. You get a list of IfStmts, start iterating, but return true / false depending on whether the firstif statement in the list is has an else block? What about the other if statements?
Even if you really did mean to check just the first if statement, I think the not-using-helper-method test would fail if productionRatePerHour used multiple returns like this community solution:
publicclassCarsAssemble {
publicdoubleproductionRatePerHour(doublespeed) {
doublebaseProductionRate = 221;
if (speed >= 1 && speed <= 4) {
returnspeed * baseProductionRate;
} elseif (speed >= 5 && speed <= 8) {
returnspeed * baseProductionRate * 0.9;
} elseif (speed == 9) {
returnspeed * baseProductionRate * 0.8;
}
returnspeed * baseProductionRate * 0.77;
}
publicintworkingItemsPerMinute(intspeed) {
return (int) productionRatePerHour(speed)/60;
}
}| public void visit(MethodDeclaration n, OutputCollector output) { | ||
| if(n.getNameAsString().equals(PRODUCTION_RATE_PER_HOUR_METHOD) && !hasHelperMethod(n)){ | ||
| output.addComment(new MethodTooLong(PRODUCTION_RATE_PER_HOUR_METHOD)); |
There was a problem hiding this comment.
I'm concerned that reusing the MethodTooLong could be confusing for the students. There's nothing in the comment that hints students should move the if statement. I think its really hard for the students to tell that they should move it a helper method because it only tells them to make the method smaller, but we actually them to specifically move the if statement into a separate method. The actionable level may be too high for this comment too.
IsaacG
commented
Sep 23, 2025
@chiarazarrella Are you still working on this? |
chiarazarrella
commented
Oct 6, 2025
Sorry, been busy with my master thesis. I will work on it for the next weeks! :) |
Closes#103
In the design.md of the exercise there is such rule:
informative: If the solution hasif/else-ifstatements in theproductionRatePerHourmethod, inform the student that creating a helper method to calculate the succes rate might make their code easier to understand.However, I reused an existing comment: method_too_long, which I think it fits with the request. The only difference is that such comment is of type
ACTIONABLE, meanwhile in thedesign.mdfile it is requested to beINFORMATIVE.ToDo: