marick / structural-typing

Structural typing for Clojure, somewhat inspired by Elm. Tailored to "flow-style" programming, where complex structures flow through a series of functions, each of which makes a smallish change. Can also be used in testing tools and the like that need to describe how a nested structure differs from a description.
MIT License
246 stars 9 forks source link

Weird interaction between structural-typing and specter #5

Closed andrioni closed 9 years ago

andrioni commented 9 years ago

Hi!

I'm having this weird interaction between structural-typing and specter, which makes specter stop working for some transformations after I require structural-typing, even in the repl.

Sample (running lein repl at the root of structural-typing):

$ lein repl
The following namespaces have an `api` function to take you to API docs:
    structural-typing.doc, such.doc
At any time, see available namespaces with `(such.api/apis)`

nREPL server started on port 62475 on host 127.0.0.1 - nrepl://127.0.0.1:62475
REPL-y 0.3.7, nREPL 0.2.10
Clojure 1.7.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_45-b14
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (require '[com.rpl.specter :as s])
nil
user=> (s/transform [s/ALL :a] inc [{:a 10}])
[{:a 11}]
user=> (require 'structural-typing.type)
nil
user=> (s/transform [s/ALL :a] inc [{:a 10}])

Exception structural-typing does not use transform  sun.reflect.NativeConstructorAccessorImpl.newInstance0 (NativeConstructorAccessorImpl.java:-2)

From what I can tell, apparently it comes from structural-typing.guts.compile.to-specter-path, but my knowledge of Clojure is not good enough to understand what's happening.

marick commented 9 years ago

Ouch. This is a consequence of changing how Specter handles keywords. Your path undoes the worst of it, but there's still the problem that Structural-Typing changes the way Specter works. The only change is handling of a nonsensical case. Specter is like Clojure:

user=> (get 1 :a)
nil
user=> (s/select [:a] 1)
[nil]

But I changed the handling of keywords to throw an error:

user=> (s/select [:a] 1)
Exception 1 is not a map  sun.reflect.NativeConstructorAccessorImpl.newInstance0 (NativeConstructorAccessorImpl.java:-2)

That's better behavior, I think, but changing the way some other library works is just wrong.