4
$\begingroup$

I tried for example

Thread[FileDate[FileNames["new*", "h:\\temp\\", 1]]]

It gives

FileDate::fstr: File specification {h:\temp\NEWEA7D.tmp,h:\temp\NEWEA7E.tmp,h:\temp\NEWEAAE.tmp} is not a string of one or more characters. >>

but still gives the right answer

Out[13]= {{2013, 11, 18, 23, 14, 32.}, {2013, 11, 18, 23, 14, 
  32.}, {2013, 11, 18, 23, 14, 32.}}

Why is there a error message? How to avoid it?

$\endgroup$
  • $\begingroup$ FileDate evaluates before Thread has a chance to perform its action. There are a few ways to fix this, the simplest one is probably this: Block[{FileDate},your-code]. $\endgroup$ – Leonid Shifrin Nov 18 '13 at 15:53
  • $\begingroup$ I seem to remember similar question discussed before, but could not find it, so I posted an answer. $\endgroup$ – Leonid Shifrin Nov 18 '13 at 16:02
8
$\begingroup$

This is a consequence of the semantics of Thread, which does not hold its arguments. This issue has been discussed many times in various Mathematica - related resources. For the case at hand, and also generally, there are several ways to avoid this issue.

The simplest solution would be to just avoid Thread here and use Map instead:

Map[FileDate, FileNames["*.nb", {"~/Documents"}, 1]]

If you insist on using Thread, then, basically, we want to prevent FileDate from evaluating before it gets appropriately threaded. In this case, this is made more complicated because we should still evaluate the inner code. One way to do this is this (I am using a slightly different code as an example):

With[{fnames = FileNames["*.nb", {"~/Documents"}, 1]},
   Thread[Unevaluated[FileDate[fnames]]]
]

in this case, we use With to inject the piece of evaluated code, and Unevaluated to prevent FileDate from evaluating before it is threaded.

One other way to do this is to use the Block trick, to make FileDate temporarily inert:

Block[{FileDate}, Thread[FileDate[FileNames["*.nb", {"~/Documents"}, 1]]]]

There are other ways to resolve this, of course.

$\endgroup$
  • $\begingroup$ Thank you Leonid Shifrin! I found `SetAttribute[FileDate,Listable] works, but I seems to remember a post say setattribute to Listable is not a good way, I can't find the post now, do you know that post? $\endgroup$ – matheorem Nov 19 '13 at 0:48
  • $\begingroup$ What is more. If you could refine this line of code, I will be appreciate. Part[#, Flatten@Position[AbsoluteTime /@Thread@FileDate[#],Max[AbsoluteTime /@Thread@FileDate[#]]]] &@FileNames["math*"]. This line of code intends to find the newest created file which has a name contained "math". I just can't eliminate the duplicate in my code, because it will involve pure function in pure function. $\endgroup$ – matheorem Nov 19 '13 at 0:53
  • $\begingroup$ @matheorem Was glad to help. Re - post: there was one I did on Listable recently, but that was about efficiency. There is another reason to advise against this, and this is that FileDate is a built-in function. Therefore, you never know what you might break by making such modifications. It may be used internally, where people assumed that it is not Listable, for example. $\endgroup$ – Leonid Shifrin Nov 19 '13 at 0:54
  • $\begingroup$ @matheorem Try this (untested): With[{fdabs = AbsoluteTime /@ Thread@FileDate[#]},Part[#, Flatten@Position[fdabs, Max[fdabs]]]]& @ FileNames["math*"]. $\endgroup$ – Leonid Shifrin Nov 19 '13 at 0:57
  • $\begingroup$ Position[fdabs, Max[fdabs]]] likes Fold but not the Fold way :) $\endgroup$ – matheorem Nov 19 '13 at 1:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.