Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Path integration #562

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

samdphillips
Copy link
Contributor

Some initial Path integration that I've been poking at for a couple of weeks now.

Initially, I used a veneer for Path.read_with and Path.write_with that were syntax and would take a block that would become the read (write) procedure. Once I started thinking about adding the other flags for reading and writing the syntax seemed too messy so I went back to a simple wrapper around call-with-input-file/call-with-output-file.

@mflatt
Copy link
Member

mflatt commented Oct 15, 2024

Crazy idea: what if we want RAAI-style with a Closeable.def form?

block:
  Closeable.def in = Port.Input.open_file("x")
  ....
  // `in.close()` is added to the end here

The Closeable.def form could be implemented roughly like this:

namespace Closeable:
  export:
    rename cdef as def
  defn.sequence_macro 'cdef $bind ... = $rhs
                         $body
                         ...':
    values(
      '
        block:
          def mutable resource = #false
          try:
            ~initially:
              resource := $rhs
            block:
              let $bind ... = resource
              $body
              ...
              #void
            ~finally:
              resource.close
      ',
      '')

@benknoble
Copy link

The closeable definition is neat; I would probably want it to return the value of the last expression in the body, personally.

@samdphillips
Copy link
Contributor Author

RAII isn't that crazy and I intended to have a more general form. I still forget sometimes that Rhombus macros can see subsequent forms in the same context. I'll take a look at implementing this.

I'm thinking that next we may want to define a Closeable interface that classes can opt into.

I agree with Ben that it might be better to return the last value instead of #void. Also, would using Closeable.defcause the final expression of the block to not be a tail call?

@mflatt
Copy link
Member

mflatt commented Oct 15, 2024

Yes, it should definitely return the value. I needed #void to cover the empty-remainder case, but didn't think through that it should be at the beginning, not the end.

Another issue with this macro implementation is that static info from $rhs should flow to resource. Maybe statiic info will have to be propagated explicitly by Closeable.def, forcing expansion of $rhs and using statinfo_meta.gather.

Note that as written, $rhs will be evaluated with breaks disabled. I think that's ok — anything not meant to be in non-breaking mode can be lifted out — but users of Closeable.def would need to be aware. Disabling breaks was intentional here to ensure that either the resource is closed on escape or it was not allocated (as long as the running thread isn't killed).

I agree about having a Closeable interface that other classes can implement, and maybe Closeable.def should require a Closeable object. The fact that close isn't called as a method above is a bug, of course.

@samth
Copy link
Member

samth commented Oct 16, 2024

I've been writing some path-related code recently, so this is helpful. How much of the racket/path library should be exposed as Path methods? Do we want something minimal here, or something that exposes basically all of racket/path (and maybe much of racket/file)?

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.

4 participants