2024 Clojure 状态调查! 中分享您的想法。

欢迎!有关本网站的更多信息,请参阅 关于 页面。

0 投票
Collections
Michael Blume 注意到 :or 默认值可能会依赖于其他键的值,见 https://groups.google.com/d/msg/clojure/6kOhpPOpHWM/ITjWwQFS_VQJ

Michael 的 Gist https://gist.github.com/MichaelBlume/4891dafdd31f0dcbc727 展示了一个涉及 :keys 和 :or 的关联形式,其编译与否取决于 :keys 中符号的顺序。通过调整此情况,可以得出始终编译但根据 :keys 产生不同值的表达式。


(let [foo 1
       bar 2
       {:keys [bar foo]
        :or {foo 3 bar (inc foo)}} {}]
  {:foo foo :bar bar})
;= {:foo 3, :bar 4}

(let [foo 1
      bar 2
      {:keys [foo bar]
       :or {foo 3 bar (inc foo)}} {}]
  {:foo foo :bar bar})
;= {:foo 3, :bar 2}


我相信最自然的解决方案是要求在封装作用域中评估 :or 默认值,其中不存在解构引入的任何局部作用域。此方法由 0001 补丁采用。

10 答案

0 投票

评论者:michaelblume

我怀疑这是正确的方法,但我认为重要的是要注意这将破坏现有的代码 https://github.com/ngrunwald/ring-middleware-format/blob/master/src/ring/middleware/format_params.clj#L214

0 投票

评论者:michaelblume

关于我之前评论的更新 —— ring-middleware-params 已经更新,不再依赖于此行为。我认为我们应该肯定合并此补丁,以免其他人依赖于它。

0 投票
by

评论者:mpenet

由于这涉及到 :or 键的评估,检查这会不会对http://dev.clojure.org/jira/browse/CLJ-1676 产生影响可能是值得的。

0 投票
by

评论者:stu

这是一个行为变化,文档并未承诺请求的行为,现有代码可能依赖于当前行为。

0 投票
by

评论者:jafingerhut

这会不会是一些现有代码之所以能够运行是因为无序映射的序列顺序是偶然的吗?如果是这样,任何依赖于现有行为的代码,当 Clojure 的映射序列在 1.5.1 到 1.6.0,然后又在 1.6.0 到 1.7.0 之间变化时,有时会崩溃,有时不会崩溃。

0 投票
by

评论者:michaelblume

是的,它确实发生了,我已经看到由于这些变化,现有代码崩溃,因此导致了讨论并产生此工单。

0 投票
by

评论者:michaelblume

更新此补丁

0 投票
by
_评论者:michalmarczyk_

@Stuart

为了证实上述所说,以下是将相同的代码片段在 Clojure 1.6 REPL 中评估,然后又在 Clojure 1.7 REPL 中再次评估所得出的结果,两个 REPL 都是新启动的,结果不同


Clojure 1.6.0
(let [foo 1 bar 2
      {:keys [foo bar]
       :or {foo 3 bar (inc foo)}} {}]
  [foo bar])
[3 2]

Clojure 1.7.0
(let [foo 1 bar 2
      {:keys [foo bar]
       :or {foo 3 bar (inc foo)}} {}]
  [foo bar])
[3 4]


在文档中并没有承诺 {{:or}} 和 {{:keys}} 之间不会有令人意外的交互,但如上所示,任何依赖于 1.6 版本行为的现有代码已经由 1.7 版本破坏。指定某些行为并在未来坚持这种行为将防止未来出现此类惊喜。

我也认为当前的行为在某种程度上是“随机的”,因为没有原则上的原因可以解释为什么人们会期望它——因此我提出了在补丁中实现的将 {{:or}} 默认值指向封装作用域的建议。
0 投票

评论者:michaelblume

更新补丁以应用于 master

0 投票
参考:https://clojure.atlassian.net/browse/CLJ-1613(由 michalmarczyk 报告)
...