3

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?

agent-j
  • 27,335
  • 5
  • 52
  • 79

1 Answers1

2

Here are two options to consider, depending on whether you are using Clojure's core data structures.

Convert from a seq to an IEnumerable<string> with Enumerable.Cast from LINQ

This 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)))

Type Hint to force the caller to supply 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.

agent-j
  • 27,335
  • 5
  • 52
  • 79