Designing a Paths Julep

Here are some examples of infix operator APIs from a few select languages (C++, Python, Haskell, Nim, Ruby).

(click me! It's long so I'm wrapping this in a toggle to not pollute the thread with walls of text:)

C++ (std::filesystem)

  • Join paths: /
  • Change file extension: .replace_extension(...)
  • Get parent directory: .parent_path()
  • Get file name: .filename()
  • Get current working directory: current_path()
  • Example:
    #include <filesystem>
    namespace fs = std::filesystem;
    fs::path base = fs::path("dir");
    fs::path path = base / "file.txt";
    auto parent = path.parent_path();
    auto newPath = path.replace_extension(".bak");
    

Python (pathlib)

  • Join paths: / or .joinpath(...)
  • Change file extension: .with_suffix(...)
  • Get parent directory: .parent
  • Get file name: .name
  • Get current working directory: Path.cwd()
  • Example:
    from pathlib import Path
    base = Path('dir')
    path = base / 'file.txt'
    parent = path.parent
    new_path = path.with_suffix('.bak')
    

Haskell (filepath package)

  • Join paths: </>
  • Change file extension: -<.>
  • String joining for extensions: <.>
  • Get parent directory: takeDirectory
  • Get file name: takeFileName
  • Get current working directory: getCurrentDirectory
  • Example:
    import System.FilePath
    base = "dir"
    path = base </> "file.txt"
    parent = takeDirectory path
    newPath = path -<.> "bak"
    

Nim (built-in)

  • Join paths: /
  • Change file extension: changeFileExt(...)
  • Get parent directory: parentDir(...)
  • Get file name: extractFileName(...)
  • Get current working directory: getCurrentDir()
  • Example:
    import os
    let base = "dir"
    let path = base / "file.txt"
    let parent = parentDir(path)
    let newPath = changeFileExt(path, ".bak")
    

Ruby (Pathname library)

  • Join paths: /
  • Change file extension: .sub_ext(...)
  • Get parent directory: .parent
  • Get file name: .basename
  • Get current working directory: Pathname.getwd
  • Example:
    require 'pathname'
    base = Pathname.new('dir')
    path = base / 'file.txt'
    parent = path.parent
    new_path = path.sub_ext('.bak')
    

I do kind of have an admiration for Haskell’s syntax but it’s probably unrealistic for Julia at this stage. Also would make more sense if <> was string concat (which it isn’t even in Haskell… weird).

Also, I continue to be surprised by how clean C++17 looks!

One theme from poking around is that nearly all languages that do have an infix operator use / apart from Haskell which uses </> instead.

5 Likes