开发者

Using C Unions with Scala

Is it possible to emulate a C union structure using Scala? I开发者_运维技巧n this case variables are overwritten each other.

Following is a list of characteristics that might be possible:

  1. With the same variable allow to use different types.
  2. Variables use the same memory location.
  3. Any way to know what types are stored.

I think that the second characteristic is the most difficult to emulate.

Thanks


One would generally use case classes to create discriminated (tagged) unions (or otherwise employ type contracts). This has a similar effect and is type-safe.

In the case class tour, you can see Var, Fun an App can all be stored in something capable of holding a Term. Then pattern matching can be used to extract what has been stored and act depending upon the specific type (Var, Fun, App, etc.) matched upon. This whole process is similar to using an extra "type" flag and if/else-construct often used with C unions only, again, type-safe (and much more convenient in most cases :-)

(Actually, looking at those links is rather disappointing as it doesn't really scratch the surface :-/)

A practical example/explanation using Scala: What is an algebraic data type? It also does the nice job of showing how it relates/is handled in "lesser" languages.


I think your best bet is Either:

var x: Either[Int, Double] = _
x = Left(5)
x = Right(1.5)
x match {
    case Left(i) => println("Int "+i)
    case Right(d) => println("Double "+d)
}

What this does not let you do is to "read" one type as if it were the other. It does uses one reference more than the size of the types alone, but it doesn't add the size taken by both types together. And it does allow you to know which type is stored.


One very common use of a union is to allow you to see (for example) a long and 3 ints represented by an array of bytes, typically for file or network I/O.

To do the equivalent in Java, and therefore in Scala, you should look at the NIO library: http://en.wikipedia.org/wiki/New_I/O This provides all the functionality you need to read/write rich values against sockets, files, etc.

You can instead use the older Reader/Writer/Stream approach (http://tutorials.jenkov.com/java-io/index.html) if you feel more comfortable with that API, and you may have more luck finding online tutorials there.


What about writing a type parametric class Union, with implicit converters from A => B and B => A

class Union [A, B] {
  getA = ...
  getB = ...
}

which would work, if every B could be stored in an A, for example. Else, an intermediate, 3rd Type might be used, to store and restore values of type A and B, let's call it C.

class Union [A, B, C] (c: C) (implicit 
  a2c: (A => C), 
  b2c: (B => C),  
  c2a: (C => A), 
  c2b: (C => B)) {
  def getA : A = c2a (c) 
  def getB : B = c2b (c)
}

As and Bs are stored as Cs, and there is a method, for A and one for B to get the value out of C again.

To use it, we take some demo-methods:

def l2i (l: List[Char]): Int = 
  (0 /: l.reverse.take (4).reverse) ((a, b) => (a * 255 + b))
def i2l (i: Int): List[Char] = 
  if (i < 255) List (i.toChar) else (i % 255).toChar :: toChars (i / 255)
def l2s (l: List[Char]): String = 
  l.mkString ("")
def s2l (s: String): List[Char] = 
  s.toCharArray.toList

and then we create a real Union (String/Int/List):

class UnionSIL (l: List[Char]) 
  extends Union [String, Int, List[Char]] 
    (l: List[Char]) (s2l, i2l, l2s, l2i) {
  def this (i: Int) = this (i2l (i))
  def this (s: String) = this (s2l (s))
}

and test it:

val ui = new UnionSIL (44) 
val us = new UnionSIL ("foobar") 
List(ui, us).foreach (u => println (u.getA + ": " + u.getB)) 

,: 44
foobar: 1846929924
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜