Allow top-level "implicit class"es by folding them into containing package-object

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Allow top-level "implicit class"es by folding them into containing package-object

Ryan Williams
The requirement that implicit classes be explicitly declared inside another object gets in my way frequently and feels like it could be relaxed.

My typical library code looks like:

package foo.bar

object Baz {
 
implicit class Baz(…) { }
}

and corresponding calling code:

import foo.bar.Baz.Baz

One of the two Baz-layers is redundant.

Logically, i want my implicit classes to be considered to live inside their nearest containing package object (in this case foo.bar), just like non-implicit classes, but I can only declare a given package object once, so to use it I have to put all classes in a package in the same file (in the package object), which is also suboptimal.

LMK if I'm missing something? Thanks!

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Allow top-level "implicit class"es by folding them into containing package-object

Jason Zaugg

Unfortunately we have a number of assumptions in our toolchain (mostly driven by the requirement of separate+incremental compilation), that each class file comes from a single source file. Package objects are modelled as an object with the name package, so like any other object they must be defined within a single source file (by convention, named package.scala.)


I believe instead that we should allow top level implicit classes and treat it as though it introduced companion object of type Function1[Wrapped, Wrapper]. The companion itself would be seen as an implicit. The call to Wrapper.apply(wrapped) couId be translated to new Wrapper(wrapped) in order to make later optimizations for implicit classes work as expected. We already do this for calls to the companion apply methods of case classes.

-jason


On Wed, 7 Dec 2016 at 13:26 Ryan Williams <[hidden email]> wrote:
The requirement that implicit classes be explicitly declared inside another object gets in my way frequently and feels like it could be relaxed.

My typical library code looks like:

package foo.bar

object Baz {
 
implicit class Baz(…) { }
}

and corresponding calling code:

import foo.bar.Baz.Baz

One of the two Baz-layers is redundant.

Logically, i want my implicit classes to be considered to live inside their nearest containing package object (in this case foo.bar), just like non-implicit classes, but I can only declare a given package object once, so to use it I have to put all classes in a package in the same file (in the package object), which is also suboptimal.

LMK if I'm missing something? Thanks!

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Allow top-level "implicit class"es by folding them into containing package-object

martin odersky-2


On Wed, Dec 7, 2016 at 5:28 AM, Jason Zaugg <[hidden email]> wrote:

Unfortunately we have a number of assumptions in our toolchain (mostly driven by the requirement of separate+incremental compilation), that each class file comes from a single source file. Package objects are modelled as an object with the name package, so like any other object they must be defined within a single source file (by convention, named package.scala.)


I believe instead that we should allow top level implicit classes and treat it as though it introduced companion object of type Function1[Wrapped, Wrapper]. The companion itself would be seen as an implicit. The call to Wrapper.apply(wrapped) couId be translated to new Wrapper(wrapped) in order to make later optimizations for implicit classes work as expected. We already do this for calls to the companion apply methods of case classes.


But there's another problem: How do you figure out that a top-level class is implicit? The compiler has only the name of the file as an entry in the enclosing package scope. It would have to look inside the file to find out whether it contained an implicit class. That would break all our assumptions about separate compilation.

  - Martin
 

On Wed, 7 Dec 2016 at 13:26 Ryan Williams <[hidden email]> wrote:
The requirement that implicit classes be explicitly declared inside another object gets in my way frequently and feels like it could be relaxed.

My typical library code looks like:

package foo.bar

object Baz {
 
implicit class Baz(…) { }
}

and corresponding calling code:

import foo.bar.Baz.Baz

One of the two Baz-layers is redundant.

Logically, i want my implicit classes to be considered to live inside their nearest containing package object (in this case foo.bar), just like non-implicit classes, but I can only declare a given package object once, so to use it I have to put all classes in a package in the same file (in the package object), which is also suboptimal.

LMK if I'm missing something? Thanks!

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Allow top-level "implicit class"es by folding them into containing package-object

Roland Kuhn

7 dec. 2016 kl. 09:51 skrev martin odersky <[hidden email]>:



On Wed, Dec 7, 2016 at 5:28 AM, Jason Zaugg <[hidden email]> wrote:

Unfortunately we have a number of assumptions in our toolchain (mostly driven by the requirement of separate+incremental compilation), that each class file comes from a single source file. Package objects are modelled as an object with the name package, so like any other object they must be defined within a single source file (by convention, named package.scala.)


I believe instead that we should allow top level implicit classes and treat it as though it introduced companion object of type Function1[Wrapped, Wrapper]. The companion itself would be seen as an implicit. The call to Wrapper.apply(wrapped) couId be translated to new Wrapper(wrapped) in order to make later optimizations for implicit classes work as expected. We already do this for calls to the companion apply methods of case classes.


But there's another problem: How do you figure out that a top-level class is implicit? The compiler has only the name of the file as an entry in the enclosing package scope. It would have to look inside the file to find out whether it contained an implicit class. That would break all our assumptions about separate compilation.

Would it be thinkable to forego separate compilation? Source files whose translation has not been invalidated since the last run could just be rehydrated from their class files (assuming that this can be made quick enough) or even kept in memory between runs. How close is this to what zinc does?

Regards,

Roland


  - Martin
 

On Wed, 7 Dec 2016 at 13:26 Ryan Williams <[hidden email]> wrote:
The requirement that implicit classes be explicitly declared inside another object gets in my way frequently and feels like it could be relaxed.

My typical library code looks like:

package foo.bar

object Baz {
 
implicit class Baz(…) { }
}

and corresponding calling code:

import foo.bar.Baz.Baz

One of the two Baz-layers is redundant.

Logically, i want my implicit classes to be considered to live inside their nearest containing package object (in this case foo.bar), just like non-implicit classes, but I can only declare a given package object once, so to use it I have to put all classes in a package in the same file (in the package object), which is also suboptimal.

LMK if I'm missing something? Thanks!

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Allow top-level "implicit class"es by folding them into containing package-object

Jason Zaugg
In reply to this post by martin odersky-2


On Wed, 7 Dec 2016 at 18:51 martin odersky <[hidden email]> wrote:
On Wed, Dec 7, 2016 at 5:28 AM, Jason Zaugg <[hidden email]> wrote:

Unfortunately we have a number of assumptions in our toolchain (mostly driven by the requirement of separate+incremental compilation), that each class file comes from a single source file. Package objects are modelled as an object with the name package, so like any other object they must be defined within a single source file (by convention, named package.scala.)


I believe instead that we should allow top level implicit classes and treat it as though it introduced companion object of type Function1[Wrapped, Wrapper]. The companion itself would be seen as an implicit. The call to Wrapper.apply(wrapped) couId be translated to new Wrapper(wrapped) in order to make later optimizations for implicit classes work as expected. We already do this for calls to the companion apply methods of case classes.


But there's another problem: How do you figure out that a top-level class is implicit? The compiler has only the name of the file as an entry in the enclosing package scope. It would have to look inside the file to find out whether it contained an implicit class. That would break all our assumptions about separate compilation.

Good point. To fit in with that constraint, we'd need some scheme to encode the implicit modifier into the name of a some class. For instance, we could do something like:
implicit class RichString(val s: String) {
   /*synthetic*/ class Implicit$ // added by the compiler
}
There is precedent for adding synthetic inner classes (e.g javac does to add to the signatures of "access constructors": https://gist.github.com/retronym/8ca8026f5b7eb981b53f5c8923d50f54)

-jason

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Allow top-level "implicit class"es by folding them into containing package-object

martin odersky-2


On Wed, Dec 7, 2016 at 11:31 AM, Jason Zaugg <[hidden email]> wrote:


On Wed, 7 Dec 2016 at 18:51 martin odersky <[hidden email]> wrote:
On Wed, Dec 7, 2016 at 5:28 AM, Jason Zaugg <[hidden email]> wrote:

Unfortunately we have a number of assumptions in our toolchain (mostly driven by the requirement of separate+incremental compilation), that each class file comes from a single source file. Package objects are modelled as an object with the name package, so like any other object they must be defined within a single source file (by convention, named package.scala.)


I believe instead that we should allow top level implicit classes and treat it as though it introduced companion object of type Function1[Wrapped, Wrapper]. The companion itself would be seen as an implicit. The call to Wrapper.apply(wrapped) couId be translated to new Wrapper(wrapped) in order to make later optimizations for implicit classes work as expected. We already do this for calls to the companion apply methods of case classes.


But there's another problem: How do you figure out that a top-level class is implicit? The compiler has only the name of the file as an entry in the enclosing package scope. It would have to look inside the file to find out whether it contained an implicit class. That would break all our assumptions about separate compilation.

Good point. To fit in with that constraint, we'd need some scheme to encode the implicit modifier into the name of a some class. For instance, we could do something like:
implicit class RichString(val s: String) {
   /*synthetic*/ class Implicit$ // added by the compiler
}
There is precedent for adding synthetic inner classes (e.g javac does to add to the signatures of "access constructors": https://gist.github.com/retronym/8ca8026f5b7eb981b53f5c8923d50f54)

-jason

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

That's an interesting idea! I had not thought of that. That could indeed solve the problem.

 - Martin

--

Martin Odersky
EPFL and Lightbend

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.