This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Monkey(patch)ing around

7 replies
Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Currently, the following code:

  case class Foo(bar: String)

translates to something like:

  class Foo(bar: String) { /* hashCode, toString, equals, Product stuff, accessors, etc */ }
  object Foo extends (String => Foo) {
    def apply(bar: String): Foo = new Foo(bar)
    /* unapply */
  }

Would it be possible to make the following code:

  implicit case class PimpedString(private val s: String) {
    def allcaps = s.map(_.toUpperCase).mkString
  }

translate to something like:

  class PimpedString(private val s: String) {
    def allcaps = s.map(_.toUpperCase).mkString
    /* ... */
  }
  implicit object PimpedString extends (String => PimpedString) {
    def apply(s: String): PimpedString = new PimpedString(s)
    /* unapply */
  }

so that the following compiles and evaluates to true:

  "wee".allcaps == "WEE"

It's a bit overkill... I'm sure I'm going to get bit in the ass by some code that expects a Product and makes all my implicit case classes kick in willy nilly... Or forgetting to make the case class parameter private and getting some oddly-named methods on all my strings that do nothing but return the same string... Not to mention all the bugs-in-waiting that I'm not even considering...

However... I'm probably willing to live with those risks. It makes monkeypatching every-so-slighter more concise than the current approach of defining a class and an implicit def. In fact, it's -almost- as concise as Ruby's open classes. It's also a fairly minor change, and the translation is entirely natural given the current semantics of case class.

What does everyone think?

--j

Jon Pretty
Joined: 2009-02-02,
User offline. Last seen 42 years 45 weeks ago.
Re: Monkey(patch)ing around

Hi Jorge,

Jorge Ortiz wrote:
> What does everyone think?

I kind of agree, and I actually proposed much the same thing a while
back, but I'm happy living without it.

Given,

implicit case class Foo(x : Int) { ... }

I think there's a case for this translating to either:

implicit def intToFoo(x : Int) : Foo = Foo(x)
case class Foo(x : Int) { ... }

or, as you suggested,

implicit object Foo { ... }
case class Foo(x : Int) { ... }

Unfortunately, I think people might use such syntax for the purposes of
the former, when they don't actually want (or expect) the more
Pandora's-box-esque effects of the latter...

Nevertheless, I don't want to kill off the discussion early, if anyone
else has any thoughts on it.

Cheers,
Jon

Szymon Jachim
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
Re: Monkey(patch)ing around
It should do both... Simple and powerful. 

On Mon, Feb 2, 2009 at 3:54 PM, Jon Pretty <jon [dot] pretty [at] sygneca [dot] com> wrote:
Hi Jorge,

Jorge Ortiz wrote:
> What does everyone think?

I kind of agree, and I actually proposed much the same thing a while
back, but I'm happy living without it.

Given,

  implicit case class Foo(x : Int) { ... }

I think there's a case for this translating to either:

  implicit def intToFoo(x : Int) : Foo = Foo(x)
  case class Foo(x : Int) { ... }

or, as you suggested,

  implicit object Foo { ... }
  case class Foo(x : Int) { ... }


Unfortunately, I think people might use such syntax for the purposes of
the former, when they don't actually want (or expect) the more
Pandora's-box-esque effects of the latter...

Nevertheless, I don't want to kill off the discussion early, if anyone
else has any thoughts on it.

Cheers,
Jon

--
Jon Pretty | Sygneca Ltd.


Jon Pretty
Joined: 2009-02-02,
User offline. Last seen 42 years 45 weeks ago.
Re: Monkey(patch)ing around

Hi Szymon,

Szymon Jachim wrote:
> It should do both... Simple and powerful.

Sorry, I should have made this clearer: the second option implies the
first, because the companion object is a subclass of a constructor
function for that thing.

And simple and powerful is a great recipe for disaster. Like giving a
hobbit a magic ring, electing the wrong president[1] or programming in
Lisp. ;-)

Cheers,
Jon

[1] As this is an apolitical forum, I won't say who I'm thinking of.

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: Monkey(patch)ing around
Hey Jon! Welcome back! Hope you're planning to stick around :)

Yeah, this (or similar) has been discussed (at least) twice before:

http://thread.gmane.org/gmane.comp.lang.scala/3455
http://www.nabble.com/Implicit-classes-(or-encouraging-people-to-pimp-hygienically)-td18192147.html

I think my present suggestion is the most minimal (compiler/spec) change possible to get something like what I want, but ideally I'd also like to avoid the nasty object creation, as per the suggestion in the second link above.

I'm toying around with a compiler plugins to see if I can get what I want with just a plugin, but I'm way out of my depth in all this Symbol/Tree/Type stuff :)

--j

On Mon, Feb 2, 2009 at 6:54 AM, Jon Pretty <jon [dot] pretty [at] sygneca [dot] com> wrote:
Hi Jorge,

Jorge Ortiz wrote:
> What does everyone think?

I kind of agree, and I actually proposed much the same thing a while
back, but I'm happy living without it.

Given,

  implicit case class Foo(x : Int) { ... }

I think there's a case for this translating to either:

  implicit def intToFoo(x : Int) : Foo = Foo(x)
  case class Foo(x : Int) { ... }

or, as you suggested,

  implicit object Foo { ... }
  case class Foo(x : Int) { ... }


Unfortunately, I think people might use such syntax for the purposes of
the former, when they don't actually want (or expect) the more
Pandora's-box-esque effects of the latter...

Nevertheless, I don't want to kill off the discussion early, if anyone
else has any thoughts on it.

Cheers,
Jon

--
Jon Pretty | Sygneca Ltd.


Jon Pretty
Joined: 2009-02-02,
User offline. Last seen 42 years 45 weeks ago.
Re: Monkey(patch)ing around

Hi Jorge!

Jorge Ortiz wrote:
> Hey Jon! Welcome back! Hope you're planning to stick around :)

Yeah, I certainly plan to (time permitting) :-)

> I'm toying around with a compiler plugins to see if I can get what I
> want with just a plugin, but I'm way out of my depth in all this
> Symbol/Tree/Type stuff :)

My limited experience of compiler plugins suggests to me that it might
just be possible to implement this without too much trouble, as long as
you're happy to write it as:

@something case class Foo(...

otherwise I think you might need to start messing with the parser...

Good luck!
Jon

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: Monkey(patch)ing around

My limited experience of compiler plugins suggests to me that it might
just be possible to implement this without too much trouble, as long as
you're happy to write it as:

  @something case class Foo(...

otherwise I think you might need to start messing with the parser...

Yup, that's the approach I'm taking. No desire whatsoever to mess with the parser :)

--j
odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.
Re: Monkey(patch)ing around

On Thu, Jan 22, 2009 at 1:38 PM, Jorge Ortiz wrote:
> Currently, the following code:
>
> case class Foo(bar: String)
>
> translates to something like:
>
> class Foo(bar: String) { /* hashCode, toString, equals, Product stuff,
> accessors, etc */ }
> object Foo extends (String => Foo) {
> def apply(bar: String): Foo = new Foo(bar)
> /* unapply */
> }
>
> Would it be possible to make the following code:
>
> implicit case class PimpedString(private val s: String) {
> def allcaps = s.map(_.toUpperCase).mkString
> }
>
> translate to something like:
>
> class PimpedString(private val s: String) {
> def allcaps = s.map(_.toUpperCase).mkString
> /* ... */
> }
> implicit object PimpedString extends (String => PimpedString) {
> def apply(s: String): PimpedString = new PimpedString(s)
> /* unapply */
> }

It would be possible, and it would easy monkeypatching.
I am just not 100% sure yet that's a good thing...

Cheers

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland