Skip to content

Make filename return Nothing for paths with no filename component (resolves #4)#6

Merged
hellerve merged 1 commit into
masterfrom
claude/filename-nothing-empty
Jul 11, 2026
Merged

Make filename return Nothing for paths with no filename component (resolves #4)#6
hellerve merged 1 commit into
masterfrom
claude/filename-nothing-empty

Conversation

@carpentry-agent

Copy link
Copy Markdown

Resolves #4.

filename returns (Maybe String), but because split never yields an empty array its Array.last was always a Just — so Nothing was unreachable and the Maybe was dishonest.

The issue offered two fixes: (a) define cases where filename should return Nothing, or (b) drop the Maybe altogether. This PR implements (a): filename now returns Nothing when the path has no filename component — i.e. when the last split component is the empty string. Otherwise it returns Just of the last component.

input result
"a/b.txt" Just "b.txt"
"foo" Just "foo"
"a/b/c" Just "c"
"" Nothing
"/" Nothing
"foo/" Nothing

Why (a) over (b): you listed it first and gave the empty-string example, it keeps the Maybe meaningful (a directory path or bare root genuinely has no filename), and it's the smaller API break — callers already had to handle Maybe, and the only ones that relied on the old "always Just, empty string for empty path" behavior are now steered toward the honest Nothing. If you'd rather go with (b) and drop the Maybe entirely, happy to redirect.

basename is implemented independently (via split/Array.prefix) and is unaffected; it was the only other internal user of the split machinery. The docstring is reversed to document the new Nothing cases, and focused tests cover each row above. No CHANGELOG.md in this repo, so nothing to add there.


Opened by the carpentry-org heartbeat agent (Claude). Veit has not reviewed this yet.

Resolves #4. filename's (Maybe String) return type was dishonest: since
split never yields an empty array, Nothing was unreachable. Now filename
returns Nothing when the last path component is empty—the empty path, a
bare root like "/", or a directory path ending in a separator—and Just
of the last component otherwise. Reverses the docstring accordingly and
adds focused tests for each case.

@carpentry-reviewer carpentry-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build & Tests

Checked out claude/filename-nothing-empty at 65e8307master (90a7235) + one commit, clean topology. Two files changed: path.carp (the fix) and test/path.carp (5 new asserts).

  • carp -x test/path.carp37 passed, 0 failed.
  • carp-fmt --check and angler: clean (rc 0). CI: both jobs green.

Findings

  • Implementation is correct and idiomatic. filename is now (Maybe.filter (Array.last &(split p)) &(fn [f] (not (String.empty? f)))). I traced the types against core: Array.last returns a copied (Maybe String), and since split never yields an empty array it's always Just; Maybe.filter's predicate is called as (~f &x), so f binds a &String, and String.empty? : (Fn [&String] Bool) matches exactly. Sound, no ref/ownership issue.
  • Probed beyond the suite. Empirically: split yields [""] for "", ["" ""] for "/", ["foo" "" ""] for "foo//"filename is Nothing for each. Just cases: "a/b/c"c, "/foo"foo, ".hidden".hidden (hidden files handled), ".". (matches os.path.basename(".")), "a/b/"Nothing. All sensible.
  • basename is independent (uses Array.prefix) and unaffected — confirmed; it's the only other split user, and there's no other caller of filename in the lib.
  • Docstring is reversed to match and reads accurately. No CHANGELOG.md in this repo (confirmed), and README.md has no filename docs — nothing else to update.

Direction note (your call)

Issue #4 offered (a) define Nothing cases or (b) drop the Maybe. This PR implements (a) — which you listed first and illustrated with the empty-string example, so it's well-grounded. Two things worth naming explicitly:

  • Merging this is the choice of (a) over (b). The code correctly implements (a); if you'd rather drop the Maybe entirely (b), this would need redirecting.
  • It's a user-facing behavior change: filename "" was Just "" (per the just-merged #3) and is now Nothing. That's exactly the intent of #4 and fine pre-0.1 — just flagging it's observable for any caller relying on the old always-Just contract.

Verdict: merge

Correct, minimal, well-tested implementation of option (a) from issue #4, with the empty-string case you named handled exactly. Builds, 37/37 pass, fmt/lint clean, no bugs found. The only open item is the (a)-vs-(b) direction, which is yours — merging commits to (a).

@hellerve
hellerve merged commit 8f7a009 into master Jul 11, 2026
2 checks passed
@hellerve
hellerve deleted the claude/filename-nothing-empty branch July 11, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

filename’s signature and implementation are confusing

1 participant