Fork me on GitHub
#clojure-spec
<
2018-01-26
>
triss14:01:37

hi all, how do I look up a functions spec at run-time? s/get-spec doesn’t seem to to work?

Alex Miller (Clojure team)14:01:16

it should if you pass it a fully-qualified symbol

triss14:01:53

ah thankyou. just spotted it said that in the docs… an I get the fully qualified symbol for a function from that function?

Alex Miller (Clojure team)14:01:27

you don’t need to get it from anywhere?

Alex Miller (Clojure team)14:01:31

user=> (defn foo [] nil)
#'user/foo
user=> (s/fdef foo :args (s/cat) :ret nil?)
user/foo
user=> (s/get-spec `foo)
#object[clojure.spec.alpha$fspec_impl$reify__2451 0x8c11eee "[email protected]"]
user=> (s/form (:args (s/get-spec `foo)))
(clojure.spec.alpha/cat)

Alex Miller (Clojure team)14:01:26

I used back-tick there - syntax quote will resolve symbols so that’s an easy way, but I also could have done (s/get-spec 'user/foo)

Alex Miller (Clojure team)14:01:55

note that what you get back is a function spec instance, but that spec supports keyword lookup of :args, :ret, and :fn

Alex Miller (Clojure team)14:01:22

or you can use s/form on it directly

user=> (s/form (s/get-spec 'user/foo))
(clojure.spec.alpha/fspec :args (clojure.spec.alpha/cat) :ret clojure.core/nil? :fn nil)

triss14:01:30

ah I see now. wonderful thank you Alex!

don.dwoske15:01:35

Rich mentioned in a podcast (I think) that there was some sugar forthcoming which allowed a map to specify/lift the namespace for all the keys in the map (if they all had the same namespace) to the map level such that each individual key in the map could be printed / declared as un namespaced for cleanliness? Is there news on this, or a preview of what it might look like? I'm working on something similar and an example would be great to see. This was mentioned in the context of using spec, so that's why I'm putting it here vs. another channel.

ghadi15:01:07

It's syntax sugar -- already in 1.9

bronsa15:01:33

#:foo{:bar 1} = {:foo/bar 1}

ghadi15:01:45

user=> *print-namespace-maps*
true
user=> {:foo/bar 42}
#:foo{:bar 42}

ghadi15:01:59

same example even

bronsa15:01:05

the universal example

the2bears15:01:01

So this foo walks into a bar. Bartender says, "Hey buddy, what kind of example you trying to set?"

don.dwoske16:01:05

Ah, missed it.. thanks @ghadi and @bronsa

triss17:01:08

ok, so if I have a function `f’ thats been passed in to another function and I don’t know it’s fully qualified name is there a way to find it?

bronsa17:01:07

if by function you mean var then yes

triss17:01:01

ah I do mean var I think - how do I look up a fully qualified name/spec for a function referenced by a variable?

triss17:01:47

oh hang on `var?' just gave me a false...

bronsa17:01:37

maybe if you give a code example of what you’re trying to do it might be clearer

triss17:01:00

I’m trying to look up if a particular function has had a spec written for it.

triss17:01:23

i.e does a function have a spec specified for it.

ghadi17:01:45

if you have a fully-qualified symbol, you can do this

ghadi17:01:07

(get (s/registry) 'my.ns/function)

ghadi17:01:17

if you have a function, you cannot

triss17:01:17

I won’t have the fully qualified symbol when I come to do it - does this mean it’s a no go?

ghadi17:01:43

"So what are you actually trying to do?"

triss17:01:46

ah ok - this is a shame - The REPL seems to be able to look up the fully-qualified symbol for function

triss17:01:46

@gihadi - it is a bit convoluted - I’m experimenting with agent based computing - and turning functions in to agents using only the information in there type signatures

triss17:01:39

(well there spec’d signatures)

ghadi17:01:02

can you turn on instrumentation prior a priori?

triss17:01:19

not what I want unfortuantely - I’m doing some crazy stuff with the spec - I unpack info about each argument and tehn search a collection for it.

triss17:01:07

the only thing I can’t do is look up wether or a not a function has had a spec written for it (when I don’t have its fully wualified name)

Alex Miller (Clojure team)17:01:05

If you don’t have the qualifier, then it’s ambiguous what you’re referring to

Alex Miller (Clojure team)17:01:42

A function of the same name could be spec ed in many nses

Alex Miller (Clojure team)17:01:16

That said, the registry is just a map with either qualified symbols or qualified keywords as keys - you could search for it

triss17:01:19

ok - thanks Alex. So is there a way to look up a functions source namespace/name?

triss17:01:18

just the function…

triss17:01:29

the REPL seems to know hwere it came from

Alex Miller (Clojure team)17:01:26

A function instance doesn’t hold an explicit name for its source var

triss17:01:02

bb-simple.core> (defn function [a] a)
#'bb-simple.core/function
bb-simple.core> (def z function)
#'bb-simple.core/z
bb-simple.core> z
#function[bb-simple.core/function]
bb-simple.core> 

triss17:01:25

so I can store a function in z - the REPL tells me where I defined it

triss17:01:13

when all I have is z is there a way to find that it refers to bb-simple.core/function?

bronsa17:01:47

not reliably

Alex Miller (Clojure team)17:01:01

that’s not the default printer - you must be running with something addition in your repl

triss17:01:40

ah - it’s the CIDER repl in emacs

Alex Miller (Clojure team)17:01:41

the function class name is a munged version of the original function name (assuming it was from a var, can be from other places too)

bronsa17:01:01

what that’s doing is using demunge to get from the class name to an approximation of the original var

bronsa17:01:14

but that is not relibale and can only be done if the function was compiled from a defn

Alex Miller (Clojure team)17:01:22

you can demunge to recover the class name, but the munge operation is not a true function (mathematically) in that multiple inputs map to the same class name

Alex Miller (Clojure team)17:01:34

that’s where the unreliability comes from

triss17:01:13

oh ok this all sounds a bit yuck. Think I’ll steer clear for now. It’s a lot of extra typing for me but such islife

Alex Miller (Clojure team)17:01:25

(Compiler/demunge (.getName (class z)))