Reputation: 2540
I am learning Scala with this book, and I have an error after trying to run one of the examples. The code:
shapes.scala
package shapes {
class Point(val x: Double, val y: Double) {
override def toString() = "Point(" + x + "," + y + ")"
}
abstract class Shape() {
def draw(): Unit
}
class Circle(val center: Point, val radius: Double) extends Shape {
def draw() = println("Circle.draw: " + this)
override def toString() = "Circle(" + center + "," + radius + ")"
}
class Rectangle(val lowerLeft: Point, val height: Double, val width: Double)
extends Shape {
def draw() = println("Rectangle.draw: " + this)
override def toString() =
"Rectangle(" + lowerLeft + "," + height + "," + width + ")"
}
class Triangle(val point1: Point, val point2: Point, val point3: Point)
extends Shape {
def draw() = println("Triangle.draw: " + this)
override def toString() =
"Triangle(" + point1 + "," + point2 + "," + point3 + ")"
}
}
shapes-actor.scala
package shapes {
import scala.actors._
import scala.actors.Actor._
object ShapeDrawingActor extends Actor {
def act() {
loop {
receive {
case s: Shape => s.draw()
case "exit" => println("exiting..."); exit
case x: Any => println("Error: Unknown message! " + x)
}
}
}
}
}
shapes-actor-script.scala
import shapes._
ShapeDrawingActor.start()
ShapeDrawingActor ! new Circle(new Point(0.0,0.0), 1.0)
ShapeDrawingActor ! new Rectangle(new Point(0.0,0.0), 2, 5)
ShapeDrawingActor ! new Triangle(new Point(0.0,0.0),
new Point(1.0,0.0),
new Point(0.0,1.0))
ShapeDrawingActor ! 3.14159
ShapeDrawingActor ! "exit"
Now I try to run the following from the command line:
scalac shapes.scala shapes-actor.scala
scala -cp . shapes shapes-actor-script.scala
The first command compiles the classes to .class
files in a directory named shapes
, but the second command raises an error:
/Users/simon/Documents/playground/code-examples/Introdu
cingScala/shapes-actor-script.scala:3: error: not found
: value shapes
import shapes._
^
...
Is it something wrong with how I am compiling / running the program?
Upvotes: 2
Views: 1696
Reputation: 4520
You seem to be treating Scala like it's Python. That unfortunately isn't going to work. I think you misunderstand what
% scala -cp . shapes shapes-actor-script.scala
means. When you execute that command, at least on OS X 10.11.5; Scala 2.11.8; Java 1.8.0_60; then you get this error:
java.io.IOException: no such file: shapes
at scala.tools.nsc.ScriptRunner.runScript(ScriptRunner.scala:194)
at scala.tools.nsc.ScriptRunner.runScriptAndCatch(ScriptRunner.scala:205)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:67)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
It complains about not being able to find shapes
because we've messed up the exec syntax. Remember the syntax is this scala -cp PATHS CLASS
, where the shell will treat PATHS
as a single argument. So the above command is telling Scala to execute the main method of a class names shapes
, which we don't have.
We might fix this by correcting the command and joinings the paths using :
. Like this:
% scala -cp .:shapes shapes-actor-script.scala
Now we're given this error:
error: error while loading ShapeDrawingActor, class file 'shapes/ShapeDrawingActor.class' has location not matching its contents: contains class ShapeDrawingActor
error: error while loading Circle, class file 'shapes/Circle.class' has location not matching its contents: contains class Circle
error: error while loading Point, class file 'shapes/Point.class' has location not matching its contents: contains class Point
error: error while loading Rectangle, class file 'shapes/Rectangle.class' has location not matching its contents: contains class Rectangle
error: error while loading Triangle, class file 'shapes/Triangle.class' has location not matching its contents: contains class Triangle
5 errors found
The issue here is two-fold:
- 1) Scala is going to recursively load every classfile for every directory you specify in the classpath. So we're double loading each file.
- 2) scala
expects directory layouts for classfiles to match package layouts, which means if we list shapes
as our sole classpath directory, and then try to load the class shapes.Triangle
then we're really trying to find and load the file shapes/shapes/Triangle.class
. That doesn't exist, so the script fails.
Let's remove shapes
from the classpath and retry:
% scala -cp . shapes-actor-script.scala
Circle.draw: Circle(Point(0.0,0.0),1.0)
Rectangle.draw: Rectangle(Point(0.0,0.0),2.0,5.0)
Triangle.draw: Triangle(Point(0.0,0.0),Point(1.0,0.0),Point(0.0,1.0))
Error: Unknown message! 3.14159
exiting...
It works!
You actually have a couple of other ways to invoke this script as well. The scala command will look for class files from .
by default, so we could have written:
% scala shapes-actor-script.scala
If you want to execute shapes-actor-script.scala
as a true script, then the simplest way is to follow the instructions here under the heading Script it!. Just add:
#!/bin/sh
exec scala "$0" "$@"
!#
...rest of shapes-actor-script.scala
You then execute it on the command line as you would any other script (make sure the file is executable!):
% ./shapes-actor-script.scala
Best of luck learning scala!
Upvotes: 2