开发者

Closing a resource stored in Option[ ]

I have a resource object stored in an option.

 private var ochan: Option[Channel] = None

At some point during program execution, ochan is set to Some(channel). I'd like to close the channel (via invoking the method close) and set the option to None in one fatal swoo开发者_开发技巧p.

Currently I have:

 def disconnect = ochan = { ochan.foreach{_.close}; None }

And previously I had:

 def disconnect = ochan = ochan.flatMap{ o => o.close; None }

Is there a better way to do this?


I'd write it like this:

def disconnect = ochan = ochan match {
  case Some(ch) => ch.close(); None
  case None => None // do nothing
}

instead of using foreach or flatMap. In my opinion, this solution shows more clearly and explicitly what happens. The solution with foreach or flatMap requires an extra mental jump, you'd have to know what these methods do on an Option.


I don't know that it's better but it's shorter (once you've defined the implicit):

implicit def closer(o: Option[Channel]) = new { 
  def close(): Option[Channel] = { o.foreach(_.close); None } 
}

def disconnect = ochan = ochan.close


There is no big difference between an immutable var and a mutable val. So why not encapsulate the behavior in a separate class, when you want to have mutability anyway?

class ChannelOption {
  private var _channel :Option[Channel] = None
  def channel = _channel
  def channel_=(ch:Option[Channel]) { _channel.foreach(_.close); _channel = ch }
}

Usage:

private val ochan = new ChannelOption
ochan.channel = Some(getAChannel)
ochan.channel.foreach(useChannel)
ochan.channel = Some(getAnotherChannel) //this automatically closes the first channel
ochan.channel = None //this automatically closes the second channel


It's not thread safe! Remember to use @volatile (not here; using synchronization), and do something like this: (this is why I don't like imperative code)

private val lock = new Object

def disconnect() {//Function has side effects: remember parenthesis!
  lock.synchronized { //Synchronizations is important; you don't want to close it multiple times
    ochan.foreach {_.close()} //Again: side effects -> parens.
  }
}

And if you don't use parallel programming, you are doing something wrong.


You could define ochan_= so that assigning a new value to ochan closes the old channel (similar to std::auto_ptr<> in C++) but I don't see how you can encapsulate that in a child class of Option[Channel] because the storage is in your class. The solution wouldn't change the code much at all, it would just make disconnect implicit by assigning ochan.


I guess this could work:

def disconnect { 
  ochan = {
    ochan.get.close
    None
  }
}

or

def disconnect {
  ochan.get.close
  ochan = None
}

Anyway since there is mutating operation, it will always need 2 calls (1 for close and one for assignment of None).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜