Skip to content

REPL should prefer REPL products #7635

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
som-snytt opened this issue Nov 27, 2019 · 10 comments · Fixed by #11148 or #12607
Closed

REPL should prefer REPL products #7635

som-snytt opened this issue Nov 27, 2019 · 10 comments · Fixed by #11148 or #12607
Assignees
Milestone

Comments

@som-snytt
Copy link
Contributor

minimized code

$ dotr
Starting dotty REPL...
scala> class C { protected val c = 42 }
// defined class C

scala> val x = C()
1 |val x = C()
  |        ^^^
  |        missing argument for parameter i of constructor C: (i: Int): C

scala>                                                                                 
$ ll C.*
-rw-r--r--  1 andrew  staff  393 Nov 27 11:11 C.class
-rw-r--r--  1 andrew  staff  349 Nov 27 11:11 C.tasty

expectation

$ scala
Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions for evaluation. Or try :help.

scala> new C
       ^
       error: not enough arguments for constructor C: (i: Int)C.
       Unspecified value parameter i.

scala> class C { protected val c = 42 }
defined class C

scala> new C
res1: C = C@b0fc838
@SethTisue
Copy link
Member

SethTisue commented Dec 9, 2019

This has bitten me as well, in a different (and perhaps likelier-to-occur) form, involving a directory instead of a .class file:

% mkdir foo
% dotr
Starting dotty REPL...
scala> def foo = 3
def foo: Int

scala> foo                                                                                                              
1 |foo
  |^^^
  |package foo is not a value

This is rather difficult to troubleshoot if you don't think to go look in the filesystem for an explanation!

@som-snytt
Copy link
Contributor Author

The related issue drives one "nuts, nuts, nuts".

$ mkdir util
$ dotr
Starting dotty REPL...
scala> import util.Try                                                          
1 |import util.Try
  |            ^^^
  |            value Try is not a member of util

Same for scalac and dotc, but again it's probably more likely that you have a stale or stray directory in the place you try out snippets in the REPL. In this case, a directory that contains nothing tasty and no class files should not introduce an eponymous package symbol.

Arguably, a package cannot be empty. The spec says, "packages are not introduced by a definition" but by that charmingly awkward phrase, "packagings." What a prescient formulation. A package exists only by virtue of packaging something.

It would also be nice if the all-knowing REPL explained all shadowings. Maybe not even a command called explain, but a mode in which it warns me when using a shadowing binding, and also overloads.

scala> util.Helper()
val res0: Helper = Helper@6048e26a   // util shadows scala.util

scala> 42 + .1
val res1 = 42.1   // I, for one, welcome our new overload overlords!

@som-snytt
Copy link
Contributor Author

som-snytt commented Jan 18, 2021

The problem is that a REPL definition doesn't shadow a definition on the class path.

➜  ~ scala
Welcome to Scala 2.13.4 (OpenJDK 64-Bit Server VM, Java 15.0.1).
Type in expressions for evaluation. Or try :help.

scala> object StringContext
object StringContext

scala> s"${42}"
       ^
       error: StringContext.type does not take parameters; signature for interpolation must be `StringContext.apply(String*)`

scala> 

Compare

➜  ~ scala
Starting scala3 REPL...
scala> object StringContext
// defined object StringContext

scala> s"${42}"
val res0: String = 42

scala> 

Edit: see below, StringContext is rooted in Scala 3. Was hi, now bye:

def test() = println {
  class StringContext(parts: String*) {
    def s(args: Any*) = "hi"
  }
  object StringContext {
    def apply(parts: String*) = new StringContext
  }
  s"bye"
}

@SethTisue
Copy link
Member

SethTisue commented Apr 7, 2021

number of days since I was bitten by this: 0

scala> val (x, y) = (42, "foo")
val x: Int = 42
val y: String = foo

scala> if (true) x else y
1 |if (true) x else y
  |          ^
  |          package x is not a value

but only because:

$ ls -ld x
drwxr-xr-x  10 tisue  staff   320B Mar  2 21:28 x/

@nicolasstucki I don't understand why this issue was closed, actually? the issue doesn't seem fixed to me, as seen above

@tpolecat
Copy link

tpolecat commented Apr 7, 2021

Yeah I was just bitten by this exact thing in the exact same way. The Scala 2 behavior seems better to me.

@som-snytt
Copy link
Contributor Author

The purpose of this bug is to move all those Fixed in Ammonite t-shirts.

@som-snytt
Copy link
Contributor Author

I took a look at the linked PR, but it went over my head. I assume it is testing something subtle that only smart people can perceive, like dog whistles or sexism if you're of a certain gender or classism if you're of a certain class or just prefer FP over OOP. Arguably, "Functions are first-class objects" is classist as well as objectifying.

@griggt
Copy link
Contributor

griggt commented May 23, 2021

This is still broken on 3.0.1-RC1-bin-SNAPSHOT-git-89e57aa (it was never actually fixed).

I took a look while working on #12303 and I believe there are (at least) two separate issues here:

  • the original example, where a class defined in the empty package that is on the classpath is not shadowed by a definition of the same name in the REPL session
  • the example that Seth raises here, where directories on the classpath are treated as packages and are not shadowed by a definition of the same name in the REPL session

I believe the first issue is the easier of the two to fix (I have some WIP around here somewhere that appears to do so).

@griggt griggt reopened this May 23, 2021
@griggt
Copy link
Contributor

griggt commented May 23, 2021

Also note that the example above using StringContext is a bad example, since Scala 3 intentionally differs from Scala 2 and desugars it to _root_.scala.StringContext:
https://github.com/lampepfl/dotty/blob/89e57aa104f9c55a6576e1a9d0e9121ef0389a70/compiler/src/dotty/tools/dotc/ast/Desugar.scala#L1684-L1685 See #4732

@som-snytt
Copy link
Contributor Author

Thanks for pointing out the change in StringContext, as it was intentionally unrooted in Scala 2. That led to a cottage industry of puzzlers.

@griggt griggt self-assigned this May 26, 2021
liufengyun added a commit that referenced this issue May 31, 2021
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants