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

warning the user at compile time about the unused bindings #448

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

wandersoncferreira
Copy link

A first solution to #444 , however there are some questions:

i) How would we handle switching it on/off? dynamic var? include a logging library and provide control through log levels?
ii) What will be the default behavior? I think it should be off. People may notice a difference in response time due to additional code that she does not sign up for.
iii) It need an explicit test or does the fact that it is running for all the tests in the suite already good enough?

I was curious to see how the clara-rules project itself would perform on this new flag. I uploaded it to a webpaste service but I can paste it here if someone want it. It has 1k lines in total.

Copy link
Collaborator

@WilliamParker WilliamParker left a comment

Choose a reason for hiding this comment

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

Regarding those questions:

i) I don't think we want to force a particular log library on users; there was some discussion of this on #425 (comment) in the context of issue 275. If there are more things to log I like the idea of an overall "development mode" where these warnings are turned on and the user supplies a logging implementation, possibly with Clara including implementation(s) for likely choices. This could be as simple as a function that takes a level keyword and a string to log.
ii) I don't think we want to run this check on each invocation of session construction. Note that this is currently cached so users may expect it to be highly performant after the first call. Only doing it by default on cache misses might be OK in terms of perf, but it could be annoying if the user knows and accepts the unused bindings e.g. if they are the consequence of some DSL built by the user and removing them would add complication to it. I know of a number of cases where Clara has been a compilation target rather than rules being directly written for it.
iii) I think we'd want an explicit test that it does indeed detect the unused bindings; it running against the test suite just demonstrates that it doesn't break existing functionality.

@@ -0,0 +1,25 @@
(ns clara.rules.logger)
Copy link
Collaborator

Choose a reason for hiding this comment

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

A binding in an accumulator constraint will cause accumulation to occur over each value of that binding, so even if it is a new binding that isn't used elsewhere it actually does impact rule semantics. So these two rules don't behave the same way:

(defrule get-current-temperature
  [?current-temp <- newest-temp :from [Temperature (= ?location location)]]
  =>
  (insert! (->CurrentTemperature ?current-temp))
  )
(defrule get-current-temperature
  [?current-temp <- newest-temp :from [Temperature]]
  =>
  (insert! (->CurrentTemperature ?current-temp))
  )

http://www.clara-rules.org/docs/accumulators/ discusses this, specifically the paragraph after the first example. So I think we need logic that excludes from this check bindings that only appear once, but where that appearance is in an accumulator.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah! I'm glad you pointed this out. I should have paid more attention. Can't this be the case for more than just an accumulator then? This may make the whole effort here need to shift to something within the compiler more than an external pass over the production structures as currently being done.

I thought this external "linting" approach was fine since we could just ignore nearly all structure and find variables. However, seeing this accumulator case reminds me there are more semantics to perhaps be aware of. The detection may be more "context dependent" than I thought...

Copy link
Author

Choose a reason for hiding this comment

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

Interesting corner case, I will write some code to handle the accumulator approach. Maybe if something else appear that is more dependent of context, we can revisit this approach of external linting.


(defn- warn-unused-binding
[{:keys [lhs rhs] :as production}]
(let [re-binding #"\?[\w-]+"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd suggest using the is-variable? function in the interest of consistency; we could factor it out into say an "analysis-utils" namespace to avoid a cyclic dependency.

@@ -0,0 +1,25 @@
(ns clara.rules.logger)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we go with this approach, I'd not call the ns "logger".

Something like analyzer or analysis seems more typical. Logging is a separate concern.

@mrrodriguez
Copy link
Collaborator

i) I don't think we want to force a particular log library on users; there was some discussion of this on #425 (comment) in the context of issue 275. If there are more things to log I like the idea of an overall "development mode" where these warnings are turned on and the user supplies a logging implementation, possibly with Clara including implementation(s) for likely choices. This could be as simple as a function that takes a level keyword and a string to log.

Agreed that we should not attempt to supply any sort of default logging infrastructure. If we want to make the logging of warnings/etc pluggable, we likely can just provide some functions via an API option and perhaps default those to stdout.

(defn- warn-unused-binding
[{:keys [lhs rhs] :as production}]
(let [re-binding #"\?[\w-]+"
constraints-bindings (->> lhs
Copy link
Contributor

Choose a reason for hiding this comment

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

super nit/style: Could these be replaced by transducers?

@EthanEChristian EthanEChristian changed the base branch from master to main July 9, 2020 15:18
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