EDIT: I keep getting upvotes here. Just for the record, I no longer think this is important. I haven\'t needed it since I posted it.
I would like to do following in
String objects are immutable in Scala (and Java). The alternatives I can think of are:
In the second scenario you would have something like:
def save(srcPath: String, destPath: StringBuilder) {
if (!destPath.toString().endsWith("/"))
destPath.append("/")
// do something
//
}
EDIT
If I understand correctly, you want to use the argument as a local variable. You can't, because all method arguments are val's in Scala. The only thing to do is to copy it to a local variable first:
def save(srcPath: String, destPath: String) {
var destP = destPath
if (!destP.endsWith("/"))
destP += "/"
// do something
//
}
Maybe you could get the type system to do the work for you, so you don't even need to worry about adding a slash each time:
class SlashString(s: String) {
override val toString = if (s endsWith "/") s else s + "/"
}
implicit def toSlashString(s: String) = new SlashString(s)
Now you don't need any code at all to change the input String
:
def save(srcPath: String, destPath: SlashString) {
printf("saving from %s to %s", srcPath, destPath)
}
val src: String = "abc"
val dst: String = "xyz"
scala> save(src, dst)
saving from abc to xyz/
True, there's a bit of setup at the start, but this will be less-so with implicit classes in version 2.10, and it removes all clutter from the method, which was what you were worried about.
Here's a couple of suggestions:
1) Update your function a bit
def save(srcPath: String, destPath: String) {
var dp = destPath
if (!dp.endsWith('/'))
dp+= '/'
// do something, but with dp instead of destPath
}
2) Create a utility function to use before calling save
def savedPath(path: String) =
if(path.endsWith("/"))
path
else
path + "/"
//call your save method on some path
val myDestPath = ...
val srcPath = ...
save(srcPath, savedPath(myDestPath))
The JVM does not allow pass-by-reference of pointers to objects (which is how you'd do this in C++), so you can't do exactly what you want.
One option is to return the new value:
def save(srcPath: String, destPath: String): String = {
val newPath = (if (!destPath.endsWith("/")) destPath+'/' else destPath)
// do something
newPath
}
Another is to create a wrapper:
case class Mut[A](var value: A) {}
def save(srcPath: String, destPath: Mut[String]) {
if (!destPath.value.endsWith("/")) destPath.value += '/'
// do something
}
which users will then have to use on the way in. (Of course, they'll be tempted to save("/here",Mut("/there"))
which will throw away the alterations, but this is always the case with pass-by-reference function arguments.)
Edit: what you're proposing is one of the biggest sources of confusion among non-expert programmers. That is, when you modify the argument of a function, are you modifying a local copy (pass-by-value) or the original (pass-by-reference)? If you cannot even modify it it is pretty clear that anything you do is a local copy.
Just do it that way.
val destWithSlash = destPath + (if (!destPath.endsWith("/")) "/" else "")
It's worth the lack of confusion about what is actually going on.
You can't.
You'll have to declare an extra var
(or use a more functional style :-)).
Simplistic example:
def save(srcPath: String, destPath: String) {
val normalizedDestPath =
if (destPath.endsWith('/')) destPath
else destPath + '/'
// do something with normalizedDestPath
}
I know this is an old question, but if you just want to reuse the argument name perhaps:
def save(srcPath: String, destPath: String) {
((destPath: String) => {
// do something
})(if (!destPath.endsWith('/')) destPath + '/' else destPath)
}