Skip to content

Conversation

@chiarazarrella
Copy link
Contributor

@chiarazarrella chiarazarrella commented Jun 7, 2025

Closes #103

In the design.md of the exercise there is such rule:

  • informative: If the solution has if/else-if statements in the productionRatePerHour method, 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 the design.md file it is requested to be INFORMATIVE.

ToDo:

  • Add website-copy comment
  • Check comments #2380

@IsaacG
Copy link
Member

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)){
Copy link
Member

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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:

public double productionRatePerHour(int speed) {
        return 221 * speed * successRate(speed);
    }

Copy link
Member

Choose a reason for hiding this comment

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

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!

Copy link

Choose a reason for hiding this comment

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

Are you saying that this is still magic?

public double productionRatePerHour(int speed) {
    int cars_per_hour = 221;
    return cars_per_hour * speed * successRate(speed);
}

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense! Apologies, I completely missed this angle. Indeed, this is not a magic number situation!

Copy link
Member

@jagdish-15 jagdish-15 Oct 16, 2025

Choose a reason for hiding this comment

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

What do you think of something like this?

private boolean useMagicNumber(CompilationUnit node) {
    List<VariableDeclarator> declarations = node.findAll(VariableDeclarator.class);

    long declarationCount = declarations.stream()
            .filter(vd -> vd.getInitializer().isPresent()
                    && vd.getInitializer().get().toString().equals(MAGIC_NUMBER))
            .count();

    long literalUsages = node.findAll(IntegerLiteralExpr.class).stream()
            .filter(lit -> lit.asString().equals(MAGIC_NUMBER))
            .count();

    return declarationCount == 1 && literalUsages == 1;
}

Copy link

Choose a reason for hiding this comment

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

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?

Copy link
Member

Choose a reason for hiding this comment

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

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!

Copy link
Member

Choose a reason for hiding this comment

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

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):

public double productionRatePerHour(int speed) {
        return 221 * 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();
Copy link
Member

Choose a reason for hiding this comment

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

Something here seems strange here. You get a list of IfStmts, start iterating, but return true / false depending on whether the first if 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:

public class CarsAssemble {

    public double productionRatePerHour(double speed) {
        double baseProductionRate = 221;

        if (speed >= 1 && speed <= 4) {
            return speed * baseProductionRate;
        } else if (speed >= 5 && speed <= 8) {
            return speed * baseProductionRate * 0.9;
        } else if (speed == 9) {
            return speed * baseProductionRate * 0.8;
        }
        return speed * baseProductionRate * 0.77;
    }

    public int workingItemsPerMinute(int speed) {
       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));
Copy link
Member

Choose a reason for hiding this comment

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

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.

@SleeplessByte SleeplessByte added x:module/analyzer Work on Analyzers x:type/coding Write code that is not student-facing content (e.g. test-runners, generators, but not exercises) x:action/create Work on something from scratch labels Jun 16, 2025
@IsaacG
Copy link
Member

IsaacG commented Sep 23, 2025

@chiarazarrella Are you still working on this?

@chiarazarrella
Copy link
Contributor Author

Sorry, been busy with my master thesis. I will work on it for the next weeks! :)

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

Labels

x:action/create Work on something from scratch x:module/analyzer Work on Analyzers x:type/coding Write code that is not student-facing content (e.g. test-runners, generators, but not exercises)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cars-assemble: implement analyzer

6 participants