Scala Programming Language
  1. Scala Programming Language
  2. SI-1931

Allow masking of predef implicits (in REPL)

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: Repl / Interpreter
    • Labels:
      None

      Description

      It would be very useful in some instances to be able to do something like "import

      {Predef.any2StringAdd => _}

      " to hide predef implicits.

        Activity

        Hide
        Iulian Dragos added a comment -

        It works, with a slightly different syntax:

        import Predef.{any2stringadd => _}
        
        class Foo {
          (new Object) + ""
        }
        

        The output:

        hiding.scala:4: error: value + is not a member of java.lang.Object
          (new Object) + ""
                       ^
        one error found
        
        Show
        Iulian Dragos added a comment - It works, with a slightly different syntax: import Predef.{any2stringadd => _} class Foo { (new Object) + "" } The output: hiding.scala:4: error: value + is not a member of java.lang.Object (new Object) + "" ^ one error found
        Hide
        Daniel Sobral added a comment -

        It works ONLY at the beginning of the file. In the example below, for instance, it won't compile with the first line uncommented, but will compile with it commented:

        import Predef.{augmentString => _} // This works
        
        object Unimport {
          val x = "x" * 5
          def main(args: Array[String]) {
            import Predef.{augmentString => _} // Here it doesn't work
            // import Predef.{wrapString => _} // This line doesn't make any difference, 
            // here or at the beginning. It looks like a bug.
            
            Console.println("x" * 5)
          }
        }
        
        Show
        Daniel Sobral added a comment - It works ONLY at the beginning of the file. In the example below, for instance, it won't compile with the first line uncommented, but will compile with it commented: import Predef.{augmentString => _} // This works object Unimport { val x = "x" * 5 def main(args: Array[String]) { import Predef.{augmentString => _} // Here it doesn't work // import Predef.{wrapString => _} // This line doesn't make any difference, // here or at the beginning. It looks like a bug. Console.println("x" * 5) } }
        Hide
        Hubert Plociniczak added a comment -

        We agreed on the last meeting that having such fine grained masking is in fact not correct, and allowing for having Predef import possibility at the beginning of the file is good enough. Unfortunately I don't remember the exact details now, but maybe Martin will want to add his 2 cents for completeness.

        Closing to the previous state.

        Show
        Hubert Plociniczak added a comment - We agreed on the last meeting that having such fine grained masking is in fact not correct, and allowing for having Predef import possibility at the beginning of the file is good enough. Unfortunately I don't remember the exact details now, but maybe Martin will want to add his 2 cents for completeness. Closing to the previous state.
        Hide
        Paul Phillips added a comment -

        That's cool, but it's been on my list to make this work right in the repl and I have no ticket for it, so I'm going to commandeer this one this nobody's using it. I need to spot those masking imports and re-run them before every successive repl command for them to have any effect.

        Show
        Paul Phillips added a comment - That's cool, but it's been on my list to make this work right in the repl and I have no ticket for it, so I'm going to commandeer this one this nobody's using it. I need to spot those masking imports and re-run them before every successive repl command for them to have any effect.
        Hide
        Johannes Rudolph added a comment -

        This is even more broken:

        try to compile this:

        import Predef.{intWrapper => _}
        
        object Test {
          println("test")
        }
        
        Show
        Johannes Rudolph added a comment - This is even more broken: try to compile this: import Predef.{intWrapper => _} object Test { println("test") }
        Hide
        Johannes Rudolph added a comment -

        Actually, I generally don't like the current behaviour for `import X.

        {bla => _}`. Right now this imports the symbol with a name (the underscore) not accessible in scope. This makes only sense if you use it in combination with a final wildcard import. Admittedly, this is as spec'd.
        Or you use the syntax at the start of a file with Predef where seems to some special casing in the compiler at work. Is this specd somewhere?

        Now if you use it in other cases, like when you've imported something in an outer scope and want to remove a symbol from inner scopes it doesn't work at all (and this is what this ticket is about) because renaming a thing in an inner scope doesn't remove it from the outer scope and because searches are done from inner to outer scope it is always found nevertheless.

        I would propose a more general solution: `import X.{bla => _}

        ` really means 'make symbol inaccessible in this scope'. This would mean, the scope which is created by this import statement would have to filter all results from the outer scopes and remove results explicitly removed by the underscore syntax from the inner scope.
        IMO this behaviour would feel more 'natural' than the current one and would play more nice with scoping in general. (If you copy-paste code into a scope and the pasted code contains the right imports you know it has the names it needs available. If pasted code instead removed things by `=> _` this removings may always be overridden by the outer scope in the current setting.)

        My feeling is that, especially with implicits being bound to scope, finer grained control is needed in some cases.

        Show
        Johannes Rudolph added a comment - Actually, I generally don't like the current behaviour for `import X. {bla => _}`. Right now this imports the symbol with a name (the underscore) not accessible in scope. This makes only sense if you use it in combination with a final wildcard import. Admittedly, this is as spec'd. Or you use the syntax at the start of a file with Predef where seems to some special casing in the compiler at work. Is this specd somewhere? Now if you use it in other cases, like when you've imported something in an outer scope and want to remove a symbol from inner scopes it doesn't work at all (and this is what this ticket is about) because renaming a thing in an inner scope doesn't remove it from the outer scope and because searches are done from inner to outer scope it is always found nevertheless. I would propose a more general solution: `import X.{bla => _} ` really means 'make symbol inaccessible in this scope'. This would mean, the scope which is created by this import statement would have to filter all results from the outer scopes and remove results explicitly removed by the underscore syntax from the inner scope. IMO this behaviour would feel more 'natural' than the current one and would play more nice with scoping in general. (If you copy-paste code into a scope and the pasted code contains the right imports you know it has the names it needs available. If pasted code instead removed things by `=> _` this removings may always be overridden by the outer scope in the current setting.) My feeling is that, especially with implicits being bound to scope, finer grained control is needed in some cases.
        Hide
        Paul Phillips added a comment -

        (In r24904) Made -Yno-predef work again, also in the repl. Fixed the "what
        do I import" code to notice root.scala.Predef too. Moved some of
        the overly specialized, called-only-once functions in treeInfo inside
        the one function which needs them. References SI-1931. No review.

        Show
        Paul Phillips added a comment - (In r24904) Made -Yno-predef work again, also in the repl. Fixed the "what do I import" code to notice root .scala.Predef too. Moved some of the overly specialized, called-only-once functions in treeInfo inside the one function which needs them. References SI-1931 . No review.
        Hide
        A. P. Marki added a comment -

        This fix was floated last summer and works the same way with replating, viz, the predef imports are pulled to the top of the compilation unit.

        apm@mara:~$ skala -cp "" 
        Welcome to Scala!
        version 2.11.0-20131104-225025-6b780988ac (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
        Type in expressions and I will evaluate them. Or try :help.
        
        scala> "hello".size
        res0: Int = 5
        
        scala> import Predef.{ augmentString => _ }
        import Predef.{augmentString=>_}
        
        scala> "hello".size
        <script>:1: error: value size is not a member of String
        "hello".size
                ^
        
        Show
        A. P. Marki added a comment - This fix was floated last summer and works the same way with replating, viz, the predef imports are pulled to the top of the compilation unit. apm@mara:~$ skala -cp "" Welcome to Scala! version 2.11.0-20131104-225025-6b780988ac (OpenJDK 64-Bit Server VM, Java 1.7.0_25). Type in expressions and I will evaluate them. Or try :help. scala> "hello".size res0: Int = 5 scala> import Predef.{ augmentString => _ } import Predef.{augmentString=>_} scala> "hello".size <script>:1: error: value size is not a member of String "hello".size ^

          People

          • Assignee:
            A. P. Marki
            Reporter:
            James Iry
            TracCC:
            Daniel Sobral, Ismael Juma, Johannes Rudolph, Paul Phillips, Seth Tisue
          • Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:

              Development