Steve B.
Steve B.

Reputation: 57333

Is there a way to include type hints inside the clojure threading macro?

For example, as in the example here,

=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
=> "X"

I'd like to be able to do something like

 => (-> ^String "a b c " .... etc etc 

to avoid the reflection penalties, esp. in interfacing with java code.

Upvotes: 3

Views: 425

Answers (3)

juan.facorro
juan.facorro

Reputation: 9930

It is possible to type hint expressions using the -> macro. While the following uses reflection:

(set! *warn-on-reflection* true)
(def s "1")
(-> s .toString)
;; Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
;;= "1"

This doesn't:

(-> ^String s .toString)
;;= "1"

Maybe if you share a specific expression where you are finding it hard or impossible to type hint we can help you better.

There is a known situation where the type hint attached to the macro's &form expression is discarded, see this JIRA ticket Macroexpansion discards &form metadata. Maybe this is what you are seeing?

Upvotes: 4

Michał Marczyk
Michał Marczyk

Reputation: 84369

Yes, it is possible.

If you need to type-hint the initial argument to ->, you can do it directly, either inside or outside the -> form:

(-> ^String (foo) .toUpperCase)

(let [^String f (foo)]
  (-> f .toUpperCase))

There will be no reflection in either case.

If the value that you wish to type-hint arises at an intermediate step in the -> chain, then you can type-hint it by putting the type hint on the -> step:

;; note the type hints on identity and (identity)

(-> ^String (foo) .toUpperCase ^String identity .toLowerCase)

(-> ^String (foo) .toUpperCase ^String (identity). toLowerCase)

Again, there will be no reflection in either case.

(Tested at a 1.7.0-alpha5 REPL.)

Upvotes: 2

Chiron
Chiron

Reputation: 20245

Well, in your case at least, there are no reflection penalties.

 user=> (set! *warn-on-reflection* true)
 true
 user=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
 "X"

If you want to be even more sure:

 user=> (def i 23)
 #'user/i
 user=> (.toString i)
 Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
 "23"

Upvotes: 1

Related Questions