This question already has answers here:
How to write to a file in Scala?
(19 answers)
Closed 6 years ago.
I am trying to write a given string into a new file in SCALA.
I have imported
java.io._
java.nio._
This is my code:
implicit class PathImplicits(p: Path) {
def write(str:String, file:String):Path = Paths.get(file)
p.write(str,file)
}
However, the compile says it does not recognize the 'file' variable.
First of all, you are missing a pair of braces around your function. I think, you intended it to look like this:
def write(str:String, file:String):Path = {
Paths.get(file)
p.write(str,file)
}
It looks like it, because str and file are parameters to the function, and you are trying to use them outside of it (a function body without braces is just one statement).
Now, the way I "fixed" it for you, still doesn't make very much sense.
First, Paths.get(file) doesn't do anything, it just returns the Path object, which you do not assign to anything, so, this call does not have any effect. Second, Path does not have a method, called write, so the second line isn't going to work. Perhaps, you intended it to implicitly end up calling PathImplicits.write, but that won't work (you'd have to be outside of that class), and that's a good thing, because you are actually inside that function, and, if that line called it again, you'd get into infinite recursion.
Let's break your problem into two parts. First, let's forget about implicits and other fancy stuff, and just figure out how to write a string into a file. There is a whole lot of different ways to do it. Here is one for instance:
def writeToFile(file: File, str: String): Unit = {
val writer = new FileWriter(file)
try { writer.append(str).append("\n") }
finally { writer.close }
}
Now, if you want to make it work with Path implicitly, you'd need something like this:
object PathImplicits {
implicit class RichPath(p: Path) extends AnyVal {
def write(str: String) = writeToFile(p.toFile, str)
}
}
That's it. Now, you should be able to write something like this:
import PathImplicits._
Paths.get("/some/path/to/file.txt").write("Foo!")
Related
I try to get names of all trait a class extends using getInterfaces which returns an array of trait's names. When I manually access each member of the array, the method getName returns simple names like this
trait A
trait B
class C() extends A, B
val c = C()
val arr = c.getClass.getInterfaces
arr(0).getName // : String = A
arr(1).getName // : String = B
However, when I use map function on arr. The resulting array contains a cryptic version of trait's names
arr.map(t => t.getName) // : Array[String] = Array(repl$.rs$line$1$A, repl$.rs$line$2$B)
The goal of this question is not about how to get the resulting array that contains simple names (for that purpose, I can just use arr.map(t => t.getSimpleName).) What I'm curious about is that why accessing array manually and using a map do not yield a compatible result. Am I wrong to think that both ways are equivalent?
I believe you run things in Scala REPL or Ammonite.
When you define:
trait A
trait B
class C() extends A, B
classes A, B and C aren't defined in top level of root package. REPL creates some isolated environment, compiles the code and loads the results into some inner "anonymous" namespace.
Except this is not true. Where this bytecode was created is reflected in class name. So apparently there was something similar (not necessarily identical) to
// repl$ suggest object
object repl {
// .rs sound like nested object(?)
object rs {
// $line sounds like nested class
class line { /* ... */ }
// $line$1 sounds like the first anonymous instance of line
new line { trait A }
// import from `above
// $line$2 sounds like the second anonymous instance of line
new line { trait B }
// import from above
//...
}
}
which was made because of how scoping works in REPL: new line creates a new scope with previous definitions seen and new added (possibly overshadowing some old definition). This could be achieved by creating a new piece of code as code of new anonymous class, compiling it, reading into classpath, instantiating and importing its content. Byt putting each new line into separate class REPL is able to compile and run things in steps, without waiting for you to tell it that the script is completed and closed.
When you are accessing class names with runtime reflection you are seeing the artifacts of how things are being evaluated. One path might go trough REPLs prettifiers which hide such things, while the other bypass them so you see the raw value as JVM sees it.
The problem is not with map rather with Array, especially its toString method (which is one among the many reasons for not using Array).
Actually, in this case it is even worse since the REPL does some weird things to try to pretty-print Arrays which in this case didn't work well (and, IMHO, just add to the confusion)
You can fix this problem calling mkString directly like:
val arr = c.getClass.getInterfaces
val result = arr.map(t => t.getName)
val text = result.mkString("[", ", ", "]")
println(text)
However, I would rather suggest just not using Array at all, instead convert it to a proper collection (e.g. List) as soon as possible like:
val interfaces = c.getClass.getInterfaces.toList
interfaces .map(t => t.getName)
Note: About the other reasons for not using Arrays
They are mutable.
Thet are invariant.
They are not part of the collections hierarchy thus you can't use them on generic methods (well, you actually can but that requires more tricks).
Their equals is by reference instead of by value.
I'm thinking if its possible to create some sort of data structure that would take a string as a parameter and if that string does not contains .txt or something like that it would give me a compile error?
I can be specific on my problem - I am trying to take a file as a parameter(Source) to a function but I am told that currently I am passing any kind of file and it only should take text files so it is not done correctly. How do i approach this?
-Thanks!! ^^
Yes, this is not a problem. The big question is should you do it though. If your code is a library of sorts then under certain circumstances this might make sense. Check out Uri.uri from the http4s project
In your case the implementation could look something like this:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
class Macros(val c: Context) {
import c.universe._
def txtFile(fileName: c.Expr[String]): Tree =
fileName.tree match {
case Literal(Constant(s: String)) if s.endsWith(".txt") =>
fileName.tree
case _ =>
c.abort(
c.enclosingPosition,
s"Supplied parameter is not a text file"
)
}
}
object MyObject {
def txtFile(fileName: String): String = macro Macros.txtFile
}
You'd use this like:
val x: String = txtFile("abc.tx") // Fails to compile
val y: String = txtFile("abc.txt") // Compiles
Again, it can be done, but you probably want to go with Option :-)
Assuming that String is coming from somewhere other than the code base (web request, cmd line), you'll need to pass that String to something that accepts Strings. Thus you'll have a point at which you're converting a String to your special filename datatype. So I can't see any way you'll be able to protect against some kind of runtime check.
If you want a runtime check that will avoid an error, you could return an Option, returning None if the String isn't a valid filename
You could use the refined library:
type TxtSuffix = EndsWith[W.`".txt"`.T]
type TxtFile = String Refined TxtSuffix
In order to construct a TxtFile, you need to give it a string that ends with ".txt":
val file: TxtFile = refineMV[TxtSuffix]("some.pdf") // compiler error
error: Predicate failed: "some.pdf".endsWith(".txt")
Say I have a local method/function
def withExclamation(string: String) = string + "!"
Is there a way in Scala to transform an instance by supplying this method? Say I want to append an exclamation mark to a string. Something like:
val greeting = "Hello"
val loudGreeting = greeting.applyFunction(withExclamation) //result: "Hello!"
I would like to be able to invoke (local) functions when writing a chain transformation on an instance.
EDIT: Multiple answers show how to program this possibility, so it seems that this feature is not present on an arbitraty class. To me this feature seems incredibly powerful. Consider where in Java I want to execute a number of operations on a String:
appendExclamationMark(" Hello! ".trim().toUpperCase()); //"HELLO!"
The order of operations is not the same as how they read. The last operation, appendExclamationMark is the first word that appears. Currently in Java I would sometimes do:
Function.<String>identity()
.andThen(String::trim)
.andThen(String::toUpperCase)
.andThen(this::appendExclamationMark)
.apply(" Hello "); //"HELLO!"
Which reads better in terms of expressing a chain of operations on an instance, but also contains a lot of noise, and it is not intuitive to have the String instance at the last line. I would want to write:
" Hello "
.applyFunction(String::trim)
.applyFunction(String::toUpperCase)
.applyFunction(this::withExclamation); //"HELLO!"
Obviously the name of the applyFunction function can be anything (shorter please). I thought backwards compatibility was the sole reason Java's Object does not have this.
Is there any technical reason why this was not added on, say, the Any or AnyRef classes?
You can do this with an implicit class which provides a way to extend an existing type with your own methods:
object StringOps {
implicit class RichString(val s: String) extends AnyVal {
def withExclamation: String = s"$s!"
}
def main(args: Array[String]): Unit = {
val m = "hello"
println(m.withExclamation)
}
}
Yields:
hello!
If you want to apply any functions (anonymous, converted from methods, etc.) in this way, you can use a variation on Yuval Itzchakov's answer:
object Combinators {
implicit class Combinators[A](val x: A) {
def applyFunction[B](f: A => B) = f(x)
}
}
A while after asking this question, I noticed that Kotlin has this built in:
inline fun <T, R> T.let(block: (T) -> R): R
Calls the specified function block with this value as its argument and returns
its result.
A lot more, quite useful variations of the above function are provided on all types, like with, also, apply, etc.
Hopefully not a silly question - scala has a lot of syntactic sugar I'm not aware of yet. I'm trying to improve as a dev and get really readible code down so that's my intention upfront.
Is it possible to create a List that will only be declared once and place it inside a method body for clarity?
I want to do this and have scala put that thing in permgen and just leave it there as it will never change.
Is it possible for this to be done or do I have to declare it in a class body.
eg
def method(param: Whatever) {
val list = List("1", "1")
}
Edit: I'm taking a wild stab that it's 'final' and I'm looking now.
Semantics require that List("1", "1") is evaluated once every time method is called, just in case the call has side-effects.
AFAIK there is no modifier that would allow you to change that behavior. If you really, really do not want to declare list in the enclosing class, you could do:
class X {
object MethodHolder {
val list = List("1", "1")
def method(param: ???) = ...
}
import MethodHolder.method
// rest of class
}
Note: You are not allowed to use the final keyword for function variables. In Scala, final does only prevent overriding (see answer to this post).
My latest problem is one that I already have a solution for, it just
feels like there should be a better way.
The problem:
I want to send a PartialUpdate to a comet service, and I need to XML
escape the string, so that when it is used on the client it gets the
correct results. I currently have:
override def lowPriority = {
case v: List[TaskOwner] => {
partialUpdate(
taskOwners.foldLeft(JsCrVar("table", Call("$", Str("table#userTable"))) &
Call("table.dataTable().fnClearTable"))((r, c) => {
r & Call("table.dataTable().fnAddData",
JsArray(Str(Text(c.name).toString),
Str(Text(c.initials).toString),
Str(makeDeleteButton(c).toString)),
Num(0))
}) & Call("table.dataTable().fnDraw"))
}
}
And this works fine, however the Str(Text(c.name).toString) feels
quite wordy to me. Now, I can, of course, create a pair of implicit
conversion functions for this, but it seems like this should have
already been done somewhere, I just don't know where. And so, in the
spirit of reducing the code that I have written, I ask if anyone knows
a better way to do this, or if the implicit conversion already exist
somewhere?
I have seen reference to a solution here. However the code is summarized as:
def xmlToJson(xml: Elem): JsExp = {
// code to map XML responses to JSON responses. Handles tricky things like always returning
// js arrays for some fields even if only 1 element appears in the XML
}
A possibly better way of escaping the names is, instead of:
JsArray(Str(Text(c.name).toString),
Str(Text(c.initials).toString),
Str(makeDeleteButton(c).toString))
to use
JsArray(Str(c.name.asHtml.toString),
Str(c.initials.asHtml.toString),
Str(makeDeleteButton(c).toString))
This can be further reduced by using an implicit within the class like:
implicit def elemToJsExp(elem: NodeSeq): JsExp = Str(elem.toString)
…
JsArray(c.name.asHtml,
c.initials.asHtml,
makeDeleteButton (c))
I don't know what Str does, but maybe you mean Str(xml.Utility.escape(c.name))?
Well, how about:
def JsStrArray(strings: String*) = JsArray(strings map xml.Utility.escape map Str : _*)
And then just use
JsStrArray(c.name, c.initials, makeDeleteButton(c).toString)
Mmmmm. It might incorrectly escape the result of makeDeleteButton. Anyway, you can play with it and see what looks good.