Skip to content

Example of ADTs in online book fails to run #2702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
djbpitt opened this issue Feb 18, 2023 · 1 comment
Closed

Example of ADTs in online book fails to run #2702

djbpitt opened this issue Feb 18, 2023 · 1 comment

Comments

@djbpitt
Copy link

djbpitt commented Feb 18, 2023

The "planets" example at https://docs.scala-lang.org/scala3/book/types-adts-gadts.html#algebraic-datatypes-adts compiles but fails to run. Tested on MacOS with Scala 3.2.2.

Code copied from example:

enum Planet(mass: Double, radius: Double):

  private final val G = 6.67300E-11
  def surfaceGravity = G * mass / (radius * radius)
  def surfaceWeight(otherMass: Double) =  otherMass * surfaceGravity

  case Mercury extends Planet(3.303e+23, 2.4397e6)
  case Venus   extends Planet(4.869e+24, 6.0518e6)
  case Earth   extends Planet(5.976e+24, 6.37814e6)

object Planet:
  def main(args: Array[String]) =
    val earthWeight = args(0).toDouble
    val mass = earthWeight / Earth.surfaceGravity
    for (p <- values)
      println(s"Your weight on $p is ${p.surfaceWeight(mass)}")

Output:

(base) djb@MacBook-Pro-10 scala % scalac bad_planets.scala
(base) djb@MacBook-Pro-10 scala % scala bad_planets.scala 100
Internal error: Detected the following main methods:
(Planet,public static void Planet.main(java.lang.String[]))
(Planet$$anon$3,public static void Planet.main(java.lang.String[]))
(Planet$$anon$1,public static void Planet.main(java.lang.String[]))
(Planet$$anon$2,public static void Planet.main(java.lang.String[]))

Working alternative code:

enum Planet(mass: Double, radius: Double):

  private final val G = 6.67300E-11
  def surfaceGravity = G * mass / (radius * radius)
  def surfaceWeight(otherMass: Double) =  otherMass * surfaceGravity

  case Mercury extends Planet(3.303e+23, 2.4397e6)
  case Venus   extends Planet(4.869e+24, 6.0518e6)
  case Earth   extends Planet(5.976e+24, 6.37814e6)

@main def main(earthWeight: Double): Unit =
  val mass = earthWeight / Planet.Earth.surfaceGravity
  for (p <- Planet.values)
    println(s"Your weight on $p is ${p.surfaceWeight(mass)}")

Output:

(base) djb@MacBook-Pro-10 scala % scalac planets.scala
(base) djb@MacBook-Pro-10 scala % scala planets.scala 100
Your weight on Mercury is 37.775761520093525
Your weight on Venus is 90.49990998410455
Your weight on Earth is 100.0

The book explains that the sample is intended to illustrate that an enum can have a companion object:

Like classes and case classes, you can also define a companion object for an enum

The revised code above does not illustrate that point, and therefore is not an equivalent example. On the other hand, the current example does not appear to run and the revision, which does run, does illustrate how to walk over the enumeration and interact with it.

@SethTisue
Copy link
Member

SethTisue commented Mar 13, 2023

I agree that it's not a great example of the point about companion objects, as there's no real reason for the main method to be inside a companion object like that. But there's no harm in having it inside a companion object, either.

The problem you're having with running the code is due to a misunderstanding about how to use the scalac and scala commands. scala bad_planets.scala 100 doesn't run the code you previously compiled with scalac; rather, it invokes the script runner.

The correct way to compile and run the code with scalac and scala is:

% /usr/local/scala/scala3-3.2.2/bin/scalac planets.scala
% /usr/local/scala/scala3-3.2.2/bin/scala Planet 100    
Your weight on Mercury is 37.775761520093525
Your weight on Venus is 90.49990998410455
Your weight on Earth is 100.0

note that I supplied scala with the name of a compiled class, not with a .scala file

As further background, note that in general, Scala users don't use the scalac and scala commands much at all; we typically compile and run our code with IntelliJ, or sbt, or Maven, or Gradle, or scala-cli. scalac and scala are of limited utility since they have no facilities for retrieving dependencies and including them on the classpath.

SIP-46 aims to replace the current scalac and scala commands with scala-cli.

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Mar 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants