b_pcakes
b_pcakes

Reputation: 2540

scala - package not found when running from command line

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

Answers (1)

Mark Kegel
Mark Kegel

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

Related Questions