- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Re: zipper
Wed, 2010-06-09, 13:26
Unfortunately it's not possible to implement it as a compiler plugin.The reason is that the code needs to be generated before type-checking(otherwise the ".loc" calls won't type-check). But it's not possible to
generate it directly after parsing either, because we need to know thingslike "is the parameter type another case class with @zip?".
So the code generation happens "somewhere" during naming / typing.
Actually, many people are fighting with that problem (generate codebefore type-checking, but still require some symbol / type informationto generate it, e.g. Kevin Wright), it would be good to solve it at some point. I see two solutions: - type-checking a first time without reporting errors, then generate the code, then type-check again. - providing some plugin-infrastructure for the namer/typer to generate code.The first approach does not work well because type-checking changesthe trees in many situations ("adapt").
Having it in 2.8 is certainly not possible, there won't be any new features.
Lukas
On Wed, Jun 9, 2010 at 13:39, Daniel Kröni <daniel.kroeni@gmail.com> wrote:
So the code generation happens "somewhere" during naming / typing.
Actually, many people are fighting with that problem (generate codebefore type-checking, but still require some symbol / type informationto generate it, e.g. Kevin Wright), it would be good to solve it at some point. I see two solutions: - type-checking a first time without reporting errors, then generate the code, then type-check again. - providing some plugin-infrastructure for the namer/typer to generate code.The first approach does not work well because type-checking changesthe trees in many situations ("adapt").
Having it in 2.8 is certainly not possible, there won't be any new features.
Lukas
On Wed, Jun 9, 2010 at 13:39, Daniel Kröni <daniel.kroeni@gmail.com> wrote:
This is just amazing! I also read Greg's blog post and realized how
cool this is but it didn't look comfortable for my use case (modifying
ASTs). Now I got exactly what I was looking for! Thank you very much.
Any chance you turn this into a compiler plugin or even put it into
the 2.8 release (I know I'm dreaming)
Cheers Daniel
On Wed, Jun 9, 2010 at 11:20 AM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
> Hi,
> inspired by Greg Meredith's blog post and Jesper Nordenberg's comment
> i implemented some code generation which allows navigating trees of case
> classes and performing functional updates on them.
> Here's an example. Suppose we model the state of a pacman game the
> following way:
>
> scala> @zip case class Pacman(lives: Int = 3, superMode: Boolean = false)
> scala> @zip case class Game(state: Symbol = 'pause, pacman: Pacman =
> Pacman())
> scala> val g = Game()
> g: Game = Game('pause,Pacman(3,false))
>
> Changing the game state to 'run is simple using the copy method:
>
> scala> val g1 = g.copy(state = 'run)
> g1: Game = Game('run,Pacman(3,false))
>
> However, changing pacman's super mode is much more cumbersome
> (and it gets worse for deeper structures):
>
> scala> val g2 = g1.copy(pacman = g1.pacman.copy(superMode = true))
> g2: Game = Game('run,Pacman(3,true))
>
> Using the compiler-generated location classes this gets much easier:
>
> scala> val g3 = g1.loc.pacman.superMode set true
> g3: Game = Game('run,Pacman(3,true))
>
>
> What happens? For a case class "@zip case class C(x: A, y: B)", suppose
> T is another case class annotated with @zip, U is any other type, the
> compiler
> generates:
>
> class CLoc[T, P <: Loc[T, _, _]](v: C, f: C => Option[P]) extends Loc[T, C,
> P](v, f) { self =>
> override def copy(v: C) = new CLoc[T, P](v, f)
> def x: ALoc[T, CLoc[T, P]] = new ALoc[T, CLoc[T, P]](v.x, (x: A) => {
> Some(self.copy(v.copy(x = x)))
> })
> def y: Loc[T, B, CLoc[T, P]] = new Loc[T, B, CLoc[T, P]](v.y, (y: B) => {
> Some(self.copy(v.copy(y = y)))
> })
> }
>
> in the class C
>
> def loc = new CLoc[C, Nothing](this, v => None)
>
> The class Loc is defined in the library as
>
> /**
> * T: top type
> * E: element type of this location
> * P: parent location type
> */
> class Loc[T, E, P <: Loc[T, _, _]](v: E, f: E => Option[P]) {
> def up: Option[P] = f(v)
> def top: T = up match {
> case Some(p) => p.top
> case _ => v.asInstanceOf[T]
> }
> def copy(v: E): Loc[T, E, P] = new Loc[T, E, P](v, f)
> def set(v: E) = copy(v).top
> }
>
>
> The prototype is on github, many things are not worked out yet e.g. generic
> case classes, case classes without copy method or name clashes.
> Comments welcome :)
> Lukas
Interestingly, I'm taking both approaches. The ultimate goal is to provide a framework for code generation based on the double-typecheck approach.
I'm trying to resist it, but it looks more and more like the best way to achieve this would be spawning a separate instance of Global for the first round of typechecking. My only main concern here is that this will cause the compiler to duplicate some work and take a performance hit.
Right now, Martin is currently 10mins down the road from me teaching a Scala course. I'll be speaking to him tonight, and my hope is that he can give me a some more insight on the compiler internals. With any luck, that should help me refine the process a bit, and optimize around any compiler slow-downs.
Failing that, it's going to have to be sorted directly in the compiler (not as a plugin), which means we'll all have to wait a bit longer :(At least we know that approach is definitely viable. After all, it already works for @BeanProperty
On 9 June 2010 13:25, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
--
Kevin Wright
mail/google talk: kev.lee.wright@gmail.com
wave: kev.lee.wright@googlewave.com
skype: kev.lee.wright
twitter: @thecoda