On 14 March 2011 10:40, Fabrizio Giudici <[email protected]>wrote:

> On 03/14/2011 11:04 AM, Kevin Wright wrote:
>
>> What a tangled web we weave...
>>
>>
> OK, Kevin. Bytecode manipulation apart (you correctly depicted the scenario
> as "vandalism" in this case and can't be avoided), does Scala add something
> interesting to the topic? :-) I'm not pulling your legs, I'm really
> interested to know whether other languages deal with it in a better way, or
> if in the end it's only a matter of design.
>
>

There's a few bits that Scala helps with.  The deep support for immutability
makes it far easier to get this code right (you don't have to worry about
missing a `final`), the collection library is a much better fit, type
inference and implicit conversions also makes some design patterns a lot
more practical, and pattern matching is a natural fit for working with
immutable objects.  The syntactic-sugar/eye candy also helps make the intent
of the code far clearer.  First class functions/closures are very relevant
too

Getting really deep, there's also a lot that can be done with type classes
and monadic comprehension to make the code cleaner and more generic, but
it's far from essential and I don't want to scare anyone off :)

File handling is such a rich topic that it's hard to know what will interest
people, so I'm just going to throw out a brain dump with some random
stuff...

m'kay?


As always, it's easier to show with some examples:

  val somedir = FileRef of "C:\somedirectory"

In this case, I'm invoking the `of` factory method on the `FileRef`
singleton.  This method accepts a URI argument, so you're also using an
implicit conversion from String=>Uri.  De-sugaring, it's equivalent to:

  val dir: FileRef = FileRef.of(Uri("C:\somedirectory"))


So how about those refs? Assuming here that we have a hierarchy something
like:

  FileRef
  - DirectoryFileRef
  - StreamableFileRef
    - AppendableFileRef
      - RandomAccessFileRef
  - NonExistantFileRef

That FileRef isn't much use as it stands, the concrete instance could be any
of those subclasses, so to print a directory list you might use pattern
matching:

  dir match {
    case x: DirectoryFileRef => println(x.contents mkString "\n")
    case _ => error(dir.toString + " is not a directory)
  }

Building on the API a bit more, you could also have an asDirectory method on
FileRef, which would return an `Option[DirectoryRef]`. Allowing that example
to be rewritten:

  dir.asDirectory foreach { d => println(d.contents mkString "\n") }

(think of Option as a collection with 0 or 1 elements, where we're supplying
a closure to be used for each element in that collection)


Combined with `containedFiles` and `subdirectories` as methods on
DirectoryFileRef, you can write code like this to print the name of the
first file in the first subdirectory:

  val dir = (FileRef of "C:\somedirectory").asDirectory
  val subDirs = dir flatMap { _.subdirectories }
  val firstSubDir = subDirs.headOption
  val subdirEntries = firstSubDir flatMap {_.containedFiles}
  val firstSubEntry = subdirEntries.headOption
  firstSubEntry foreach { println("first subentry is " + _) }

`headOption` will return the first element of a collection as an Option
(None if it's called on an empty collection).  So no risk of NPEs here!

It's guaranteed not to throw an exception (notwithstanding some catastrophic
problem in the filesystem), but still a bit verbose.

You can also do the same thing more cleanly with a for-comprehension.
 Including filtering and returning a collection for further processing:

  val tmpFiles = for {
    dir <- fileRef.asDirectory
    subdir <- dir.subdirectories filter (_.name startsWith "temp")
    files <- subdir.containedFiles filter (_.extension == "tmp")
    file <- files
  } yield file

Much cleaner :)


To work with file contents, you can then use closures, following a pattern
similar to Jdbc Templates in Spring.
Given an update method that accepts a RandomAccessFileRef and a closure, you
can then write (glossing over the need to handle string and byte-based files
differently):

  val fileRef: RandomAccessFileRef = ...
  File.update(fileRef) { contents => contents ++ "New last line\n" }

or

  File.update(fileRef){ someLongComplicatedFunctionTakingAContentsArgument }

This would handle resource management, file opening/closing, etc. for you.

Could probably think of a lot more, but I've already rambled far too much as
it is.





-- 
Kevin Wright

gtalk / msn : [email protected]
<[email protected]>mail: [email protected]
vibe / skype: kev.lee.wright
quora: http://www.quora.com/Kevin-Wright
twitter: @thecoda

"My point today is that, if we wish to count lines of code, we should not
regard them as "lines produced" but as "lines spent": the current
conventional wisdom is so foolish as to book that count on the wrong side of
the ledger" ~ Dijkstra

-- 
You received this message because you are subscribed to the Google Groups "The 
Java Posse" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/javaposse?hl=en.

Reply via email to