I have a large lazy seq of lines that I want to write to a file. In C#, I would use System.IO.File/WriteAllLines
which has an overload where the lines are either string[]
or IEnumerable<string>
.
I want to do this without using reflection at runtime.
(set! *warn-on-reflection* true)
(defn spit-lines [^String filename seq]
(System.IO.File/WriteAllLines filename seq))
But, I get this reflection warning.
Reflection warning, ... - call to WriteAllLines can't be resolved.
In general I need to know when reflection is necessary for performance reasons, but I don't care about this particular method call. I'm willing to write a bit more code to make the warning go away, but not willing to force all the data into memory as an array. Any suggestions?
Here are two options to consider, depending on whether you are using Clojure's core data structures.
IEnumerable<string>
with Enumerable.Cast
from LINQThis option will work for any IEnumerable
that contains only strings.
(defn spit-lines [^String filename a-seq]
(->> a-seq
(System.Linq.Enumerable/Cast (type-args System.String))
(System.IO.File/WriteAllLines filename)))
IEnumerable<string>
If you want to use a type hint, do this. But watch out, the clojure data structures do not implement IEnumerable<String>
, so this could lead to a runtime exception.
^|System.Collections.Generic.IEnumerable`1[System.String]|
Wrapping the full CLR name of the type in vertical pipes (|
) lets you specify characters that are otherwise illegal in Clojure syntax.
(defn spit-lines [^String filename ^|System.Collections.Generic.IEnumerable`1[System.String]| enumerable-of-string]
(System.IO.File/WriteAllLines filename enumerable-of-string))
Here's the exception from (spit-lines "filename.txt" #{})
when passing a set to the type-hinted version:
System.InvalidCastException: Unable to cast object of type 'clojure.lang.PersistentTreeSet' to type 'System.Collections.Generic.IEnumerable`1[System.String]'.
More information about specifying types.