- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Monkey(patch)ing around
Thu, 2009-01-22, 13:39
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
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
Mon, 2009-02-02, 16:17
#2
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:
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.
Mon, 2009-02-02, 16:27
#3
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.
Mon, 2009-02-02, 20:37
#4
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:
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.
Tue, 2009-02-03, 00:27
#5
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
Tue, 2009-02-03, 01:07
#6
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
Fri, 2009-02-06, 00:17
#7
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









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