On 14 March 2011 14:46, Alexey Zinger <[email protected]> wrote:

> I see a small problem with the Scala stuff.  Specifically:
>
>   FileRef
>   - DirectoryFileRef
>   - StreamableFileRef
>     - AppendableFileRef
>       - RandomAccessFileRef
>   - NonExistantFileRef
>
> How does this address the scenario of a non-existent file reference
> "becoming" existent by a side-effect of code elsewhere (maybe outside
> current execution thread, or the JVM as a whole)?  But in general, this just
> feels like a losing battle to me -- trying to apply immutability principles
> to I/O.  Why?
>
> Alexey
>
>
It's just a class hierarchy, absolutely nothing tied to Scala here :)

I'm imagining something more like:

class Uri { ... } //immutable

object Uri { //singleton
  implicit def fromString(s: String) = ... might return a FilePath ...
}

class FilePath extends Uri { //immutable
  def nativeValue: String = ...
}

trait FileRef { //possibly mutable
  asDirectory: Option[DirectoryRef]
  asStreamable: Option[StreamableFileRef]
  asAppendable: Option[AppendableFileRef]
  asRandomAccess: Option[RandomAccessFileRef]
}

object FileRef { //singleton
  def of(uri: Uri): fileRef = ...
}

object FileSystem { //singleton
  def delete(uri: Uri): Unit = ...
  def rename(from: Uri, to: Uri) = ...
}


>
> ------------------------------
> *From:* Kevin Wright <[email protected]>
> *To:* Fabrizio Giudici <[email protected]>
> *Cc:* [email protected]; Alexey Zinger <[email protected]>
> *Sent:* Mon, March 14, 2011 9:04:31 AM
> *Subject:* Re: [The Java Posse] Some design questions (about immutability
> and other stuff)
>
>
>
> 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
>
>
>


-- 
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