Skip to content

review: read-attributes, read-attributes* fns attributes arg #253

@lread

Description

@lread

Issue

read-attributes is a clojure-friendly version of read-attributes*.

But... while read-attributes will accept a class for attributes arg, read-attributes* will fail if this is done.

Repro

Setup:

(require '[babashka.fs :as fs])

(spit "foo" "foo")

I can get the basic file attributes with read-file-attributes* via class, like so:

(fs/read-attributes* "foo" java.nio.file.attribute.BasicFileAttributes)
;; => #object[sun.nio.fs.UnixFileAttributes$UnixAsBasicFileAttributes 0x7f082a4b "sun.nio.fs.UnixFileAttributes$UnixAsBasicFileAttributes@7f082a4b"]

The equivalent via string attributes:

(fs/read-attributes* "foo" "basic:*")
;; => {"lastAccessTime" #object[java.nio.file.attribute.FileTime 0x815f84b "2026-04-13T15:15:36.252890688Z"], "lastModifiedTime" #object[java.nio.file.attribute.FileTime 0x72ee0f3d "2026-04-13T15:15:36.252890688Z"], "size" 3, "creationTime" #object[java.nio.file.attribute.FileTime 0x335df4df "2026-04-13T15:15:36.252890688Z"], "isSymbolicLink" false, "isRegularFile" true, "fileKey" #object[sun.nio.fs.UnixFileKey 0x2434f0ef "(dev=802,ino=20868808)"], "isOther" false, "isDirectory" false}

(notice the return value changes to map when fetching via string, this is an underlying JDK API thing).

Now when I move to read-attributes, I can use a string attribute:

(fs/read-attributes "foo" "basic:*")
;; => {:creationTime
;;     #object[java.nio.file.attribute.FileTime 0x4e91e01e "2026-04-13T15:15:36.252890688Z"],
;;     :isSymbolicLink false,
;;     :isOther false,
;;     :lastAccessTime
;;     #object[java.nio.file.attribute.FileTime 0x592c0ff5 "2026-04-13T15:15:36.252890688Z"],
;;     :isRegularFile true,
;;     :size 3,
;;     :lastModifiedTime
;;     #object[java.nio.file.attribute.FileTime 0x6bd67295 "2026-04-13T15:15:36.252890688Z"],
;;     :fileKey #object[sun.nio.fs.UnixFileKey 0xa637dac "(dev=802,ino=20868808)"],
;;     :isDirectory false}

But... when I try read-attributes with a class attribute, it fails:

(fs/read-attributes "foo" java.nio.file.attribute.BasicFileAttributes)
;; => Execution error (IllegalArgumentException) at babashka.fs/read-attributes (fs.cljc:917).
;;    Don't know how to create ISeq from: sun.nio.fs.UnixFileAttributes$UnixAsBasicFileAttributes

Observation

Neither read-attributes nor read-attributes* mentions supported types for attributes args, but the implementation supports both string and class variants.

I guess that most folks would pass in a string attribute? It seems the more clojure-friendly option.

As for the differing return values, would a bb fs user ever prefer/need the class variant that the class attribute returns over the map that basic:* returns?

Option 0: Do nothing

Assume folks will be using string attributes.

Pros:

  • no work for us

Cons:

  • unclear for users

Option 1: Document read-attributes and read-attributes* accept string attributes arg

Leave the class attributes args as an undocumented/unsupported feature.

Pros:

  • documents common/recommended use case

Option 2: Document attributes arg types and returns for read-attributes* and read-attributes

For read-attributes this would mean documenting that we only suport a string attributes arg.

For read-attributes* this would mean documenting string and class attributes arg. And their effect on return value type.

Pros:

  • describes implementations

Cons:

  • more to read/understand for users

Option 3: Support class attributes arg for read-attributes

Pros:

  • Symmetry read-attributes* and read-attributes

Cons:

  • I don't think this would be easy, as I don't see JDK support for conversion.

Proposal

If we assume that bb fs users would prefer to specify attributes as a string and have no real need for a class version of attributes (over the map variant), then I think Option 1: doc string attributes arg only makes sense.

What do you think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions