mumuki / mulang

:bamboo: Universal, Multi Language, Multi Paradigm code analyzer
https://mumuki.github.io/mulang
GNU General Public License v3.0
124 stars 9 forks source link

not:Assigns expectation fails when assignment has same name as method #342

Open julian-berbel opened 2 years ago

julian-berbel commented 2 years ago

We have a not assigns expectation in an exercise where the student is expected to return the result of filtering a list. Some of the students however are doing something to the effect of:

module Juegoteca
  ...

  def self.juegos_violentos
    juegos_violentos = juegos.select { ... }
  end
end

The expectation is defined as Expectation "juegos_violentos" "Not:Assigns", however, we've noticed that when the assignment carries the same name as the method that contains it, the expectation does not fail. Changing the assignment to anything else will cause it to work properly.

The following test showcases this behavior:

it "Detects assignment when name is the same as method" $ do
    let notAssigns = Expectation "juegos_violentos" "Not:Assigns"
    let code = Object "Juegoteca" $
                SimpleMethod "juegos_violentos" [] $
                  Assignment "juegos_violentos" (MuNumber 123)

    runAst code [notAssigns] `shouldReturn` (result [failed notAssigns] [])
flbulgarelli commented 2 years ago

Unfortunately, this is the expected behaviour.

Mulang will check juegos_violentos does not perform any assignments by ensuring there is at least one binding that satisfies such condition. Thus, from mulang's POV it is true - there is at least a way of proving that juegos_violentos does not perform assignments, which happens to be the juegos_violentos variable.

In prolog terms, mulang is intentionally designed to evaluate that inspection as binding(juegos_violentos, Binding), not(assigns(Binding)) instead of forall(binding(juegos_violentos, Binding), not(assigns(Binding)).

However, you can still fix this problem by using a more specific binding: Juegoteca.juegos_violentos Not:Assigns. I have not tested it, but it should work.

Another theoretical alternative may be using a custom exception like the following:

though `juegos_violentos` count(assigns) = 0 

However, assigns is not yet a supported counter, yet: https://mumuki.github.io/mulang/edlspec/#supported-counters

In the future we may add add a forall-like operator, but I think it is currently out of scope.

julian-berbel commented 2 years ago

I see! that makes sense!

However, you can still fix this problem by using a more specific binding: Juegoteca.juegos_violentos Not:Assigns. I have not tested it, but it should work.

Gave it a try but I got the same behavior; could it be interpreting the juegos_violentos part of the inspection as the assignment itself instead of the method?