Arc Forumnew | comments | leaders | submitlogin
2 points by waterhouse 2884 days ago | link | parent

I'm afraid I'll have to nitpick.

1. It specifically says "Append the second line "world" to the file." Not just print those two lines, but print the first line and then append the second line to the file.

2. Your code doesn't close the output port. This really isn't a problem in a basic example like this, but if you did it repeatedly...

  arc> (repeat 4000 (w/stdout (outfile "fileio.txt") prn!hello prn!world))
  Error: "open-output-file: cannot open output file: \"/[elided]/fileio.txt\" (Too many open files; errno=24)"
Most of the examples on that page do append and do close their files. So... here's my version, which I think is more correct.

  (w/outfile f "fileio.txt"
    (disp "hello\n" f))
  (w/appendfile f "fileio.txt"
    (disp "world\n" f))
  (pr:cadr:readfile "fileio.txt")
Incidentally, "(w/stdout f prn!hello)" is just a little bit longer than "(disp "hello\n" f)".

1 point by evanrmurphy 2884 days ago | link

1. It specifically says "Append the second line "world" to the file." Not just print those two lines, but print the first line and then append the second line to the file.

True, but then under Clarification, it says: "You don't need to reopen the text file after writing the first line." I'd thought that continuous write would pass for writing and then appending with the same file open, but I guess it doesn't.

The non-closed output port is a very good point though, and that disp makes it shorter is clever.


Update: I submitted your version to with an attribution.


1 point by waterhouse 2884 days ago | link

Cool, I have been attributed! :-) I feel I have to make another embarrassing nitpick, though, which is that we want the second line, rather than the second s-expression (they happen to be the same here, but the task is to demonstrate how to do these things). I would therefore go for one of these as the third piece of code:

  (w/infile f "fileio.txt"
    (pr:cadr:lines:allchars f))

  ; Or, though this doesn't close the input port:
  (pr:cadr:lines:allchars:infile "fileio.txt")

  ; Both of the above, though fun, will read all characters
  ;  in the file, only to return the second line. Better:
  (w/infile f "fileio.txt"
    (prn readline.f))


1 point by evanrmurphy 2883 days ago | link

How about this variation of your latest:

  (w/infile f "fileio.txt"
    (repeat 2 (= l readline.f))
    (prn l))
While a bit longer, it eliminates the duplication of readline.f and addresses the concern about not reading "world" into a variable.


1 point by waterhouse 2883 days ago | link

The original spec says this...

  4. Read the second line "world" into an input string.
  5. Print the input string to the console.
Is an "input string" a variable? I guess it can't be much else... Ok. And I would put "prn.l" instead of "(prn l)"--not that it makes much difference, but I really like using ssyntax. Otherwise, I think I'm satisfied with this code.

And we've all written variations on this here, don't worry about calling it mine. It's a piece of code that we are collectively beating (or artfully crafting) into shape.


3 points by fallintothis 2882 days ago | link

Otherwise, I think I'm satisfied with this code.

Never fear! I'll show up to flog this horse in the nick of time! Y'know, before rigor mortis sets in.

Here's another I/O utility I think would be useful.

  (def readlines (n (o str (stdin)))
    (let line nil
      (repeat n (= line (readline str)))
It undoubtedly sets a variable (just not a global), though I think the "challenger" phrased the requirement as such because of a C-centric view: allocate a chunk of memory for the string, then read the string into there (which, technically, even a simple (readline) does). Anyway... With all of these, the Arc code would look something like

  (tofile   "fileio.txt" (prn "hello"))
  (ontofile "fileio.txt" (prn "world"))
  (fromfile "fileio.txt" (prn (readlines 2)))
And I don't think I could squeeze more out of that without getting overly specific. Of course, readlines is a conventional name for something that just reads all the lines of a stream, but I think we could reasonably use names closer to Arc's allchars and filechars.

  (def all-lines ((o str (stdin)))
    (drain (readline str)))

  (def filelines (name)
    (fromfile name (all-lines)))
Not sure if the latter should be hyphenated, though.