views:

133

answers:

3

Simple problem: I am subclassing a FilterInputStream in Scala, which has a read method:

public void read(byte [] b,int offset,int len)

The data being read will be put in b, but as parameters are "vals" in Scala methods, I see no way to properly subclass this. How do I set b to the data being read? The Java *InputStream really leaves me not much choice....

+9  A: 

You can put an item into b at index i simply by doing b(i) = whatever. That b is a val doesn't have an effect on this. It just means that you can't reassign b (which wouldn't be useful to do anyway).

sepp2k
Thanks, that's it. I considered the array itself immutable - which it need not be. Funny that I never ran into this so far (most of my code is pure Scala, and then you use different patterns - at least I do :-)
Maarten
+5  A: 
def read(b: Array[Byte], offset: Int, len: Int): Unit

is equivanet to following in Java:

public void read(final byte[] b, final int offset, final int len)

The array b is still mutable, and you can modify its contents.

missingfaktor
Sometimes I wonder where @missingfaktor find the time to be everywhere :-)
olle kullberg
@olle kullberg I think, it's a team of developers working under one account :)
Vasil Remeniuk
LOL. :D ` ` ` ` ` `
missingfaktor
+3  A: 

Just declaring something as a val instead of a var in Scala doesn't make it immutable. In fact, var can name an immutable value. The thing to remember is that variables in Scala, much like variables in Java, are always* references, or handles, rather than actually containing the value.

Try this in your REPL:

class Container { var content: String = "default" }
val a = new Container
val b = a
b.content = "modified"
println(a.content)

When you run val b = a you are making b and a names for the same thing (not a copy, the exact same instance of Container). Because of this, when you run b.content = "modified" the change is reflected in a as well; it is just another name for the same thing. Note this happens even though a is a val. All the val means is that you can't change what instance a is a name for.

Now think about this slight variation:

class Container { var content: String = "default" }
def update(c: Container) { c.content = "modified" }
val a = new Container
update(a)
println(a.content)

When you call update, its parameter c is also a reference or alias for a. So changes are reflected outside the method call the same way they are in the earlier example.

Arrays are mutable, so they work like this as well.

*: Primitive variables (bytes, doubles, ints, etc.) are not references in Java; their boxed equivalents (java.lang.Byte...) are. It doesn't show that much since these classes/types are immutable anyway.

David Winslow