Re: [scala-user] Phantom types

View: New views
6 Messages — Rating Filter:   Alert me  

Parent Message unknown Re: [scala-user] Phantom types

by Rafael de F. Ferreira-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks for the plug. I would really appreciate if anyone has comments
or criticisms to make.

Also, I was wondering if there is any way to remove the boilerplate
from the code. It becomes apparent when looking at the version with
abstract members (http://snippets.dzone.com/posts/show/5741).

Leaving aside the phantom types, it is easy to define a BuilderPart
class to encapsulate each field (a thin wrapper over Option[] that
returns the builder for method chaining); the price is a little
mutable state. But when the types are added to the picture, I can't
think of a way to avoid threading them all in each builder method.
Moreover, when threading the types, I couldn't find a way to avoid
threading the values as well.

PS: Curiously, when looking around for a solution to avoid threading
the values, I implemented a pseudo-dependent Map very similar to the
one Sean proposed earlier today. Just  an amusing coincidence :)

PS2: No grains of barley were harmed in the writing of the blog post.

On Wed, Jul 9, 2008 at 2:08 PM, James Iry <jamesiry@...> wrote:
> Here's somebody having fun (and getting drunk) with Scala's type system:
>
> http://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html
>



--
Rafael de F. Ferreira.
http://www.rafaelferreira.net/

Re: Re: [scala-user] Phantom types

by Henry Ware-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Jul 9, 2008 at 6:26 PM, Rafael de F. Ferreira
<rafael@...> wrote:

> Also, I was wondering if there is any way to remove the boilerplate
> from the code. It becomes apparent when looking at the version with
> abstract members (http://snippets.dzone.com/posts/show/5741).
>
> Leaving aside the phantom types, it is easy to define a BuilderPart
> class to encapsulate each field (a thin wrapper over Option[] that
> returns the builder for method chaining); the price is a little
> mutable state. But when the types are added to the picture, I can't
> think of a way to avoid threading them all in each builder method.
> Moreover, when threading the types, I couldn't find a way to avoid
> threading the values as well.

The boilerplate for the values in the anonymous ScotchBuilders can be
 abstracted into a common parent.  I also don't see anyway to avoid repeating
the types.

   class DefaultBuilder[a,b,c](default:ScotchBuilder) extends ScotchBuilder {
          protected[BuilderPattern] val theBrand:Option[String] = default.theBrand;
          protected[BuilderPattern] val theMode:Option[Preparation] = default.theMode;
          protected[BuilderPattern] val theDoubleStatus:Option[Boolean] =
default.theDoubleStatus;
          protected[BuilderPattern] val theGlass:Option[Glass] = default.theGlass;
          type HAS_BRAND = a;
          type HAS_MODE = b;
          type HAS_DOUBLE_STATUS = c;
    }

    def withBrand(b:String) = new
DefaultBuilder[TRUE,self.HAS_MODE,self.HAS_DOUBLE_STATUS](self) {
          override protected[BuilderPattern] val theBrand:Option[String] = Some(b);
    }

    def withMode(m:Mode) = new
DefaultBuilder[self.HAS_BRAND,TRUE,self.HAS_DOUBLE_STATUS](self) {
          override protected[BuilderPattern] val theMode:Option[Preparation] = Some(m);
    }

On the other hand, while the Phantom Types are very cool, going further down
the abstract member path might be more practical--- at least for the
required fields:

  case class OrderOfScotch (val brand:String, val mode:Preparation,
val glass:Option[Glass], val double:Boolean);
  abstract case class ScotchBuilder {
        self :ScotchBuilder =>
        val theBrand:String;
        val theMode:Preparation;
        val theGlass:Option[Glass]=None;
        val double:Boolean;

        // optional fields can be like before
        def withGlass(g:Glass)=new ScotchBuilder{
             val theBrand=self.theBrand;
             val theMode=self.theMode;
             val double=self.double;
             override val theGlass=Some(g);
        }

        def build=new OrderOfScotch(theBrand,theMode,theGlass,double);
  }

  def main(argv:Array[String]){
        val b=new ScotchBuilder { val theBrand="Glen Ordinal"; val
theMode=Neat; val double=false; }
        println(b);
        println(b.build);
  }

-Henry Ware

Parent Message unknown Fwd: Re: [scala-user] Phantom types

by Rafael de F. Ferreira-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Jul 9, 2008 at 9:40 PM, Henry Ware <henryware@...> wrote:

> On Wed, Jul 9, 2008 at 6:26 PM, Rafael de F. Ferreira
> <rafael@...> wrote:
>> Also, I was wondering if there is any way to remove the boilerplate
>> from the code. It becomes apparent when looking at the version with
>> abstract members (http://snippets.dzone.com/posts/show/5741).
>>
>> Leaving aside the phantom types, it is easy to define a BuilderPart
>> class to encapsulate each field (a thin wrapper over Option[] that
>> returns the builder for method chaining); the price is a little
>> mutable state. But when the types are added to the picture, I can't
>> think of a way to avoid threading them all in each builder method.
>> Moreover, when threading the types, I couldn't find a way to avoid
>> threading the values as well.
>
> The boilerplate for the values in the anonymous ScotchBuilders can be
>  abstracted into a common parent.  I also don't see anyway to avoid repeating
> the types.
>
>   class DefaultBuilder[a,b,c](default:ScotchBuilder) extends   ScotchBuilder {
>          protected[BuilderPattern] val theBrand:Option[String] = default.theBrand;
>          protected[BuilderPattern] val theMode:Option[Preparation] = default.theMode;
>          protected[BuilderPattern] val theDoubleStatus:Option[Boolean] =
> default.theDoubleStatus;
>          protected[BuilderPattern] val theGlass:Option[Glass] = default.theGlass;
>          type HAS_BRAND = a;
>          type HAS_MODE = b;
>          type HAS_DOUBLE_STATUS = c;
>    }
>
>    def withBrand(b:String) = new
> DefaultBuilder[TRUE,self.HAS_MODE,self.HAS_DOUBLE_STATUS](self) {
>          override protected[BuilderPattern] val theBrand:Option[String] = Some(b);
>    }
>
>    def withMode(m:Mode) = new
> DefaultBuilder[self.HAS_BRAND,TRUE,self.HAS_DOUBLE_STATUS](self) {
>          override protected[BuilderPattern] val theMode:Option[Preparation] = Some(m);
>    }
>

That's cool. I hadn't thought of that.

> On the other hand, while the Phantom Types are very cool, going further down
> the abstract member path might be more practical--- at least for the
> required fields:
>
>  case class OrderOfScotch (val brand:String, val mode:Preparation,
> val glass:Option[Glass], val double:Boolean);
>  abstract case class ScotchBuilder {
>        self :ScotchBuilder =>
>        val theBrand:String;
>        val theMode:Preparation;
>        val theGlass:Option[Glass]=None;
>        val double:Boolean;
>
>        // optional fields can be like before
>        def withGlass(g:Glass)=new ScotchBuilder{
>             val theBrand=self.theBrand;
>             val theMode=self.theMode;
>             val double=self.double;
>             override val theGlass=Some(g);
>        }
>
>        def build=new OrderOfScotch(theBrand,theMode,theGlass,double);
>  }
>
>  def main(argv:Array[String]){
>        val b=new ScotchBuilder { val theBrand="Glen Ordinal"; val
> theMode=Neat; val double=false; }
>        println(b);
>        println(b.build);
>  }

In this case we probably should do away with the builder entirely and
define the abstract members directly on the class being created
(OrderOfScotch in the example).

>
> -Henry Ware
>

--
Rafael de F. Ferreira.
http://www.rafaelferreira.net/

Re: Re: [scala-user] Phantom types

by Rob Dickens-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

In exchange for type safety, it looks as though you have to give up the ability to build the end result in stages. See the comment (@rob) I've just added. Please correct me if I'm wrong.

Rob

On Wed, Jul 9, 2008 at 11:26 PM, Rafael de F. Ferreira <rafael@...> wrote:
Thanks for the plug. I would really appreciate if anyone has comments
or criticisms to make.

Also, I was wondering if there is any way to remove the boilerplate
from the code. It becomes apparent when looking at the version with
abstract members (http://snippets.dzone.com/posts/show/5741).

Leaving aside the phantom types, it is easy to define a BuilderPart
class to encapsulate each field (a thin wrapper over Option[] that
returns the builder for method chaining); the price is a little
mutable state. But when the types are added to the picture, I can't
think of a way to avoid threading them all in each builder method.
Moreover, when threading the types, I couldn't find a way to avoid
threading the values as well.

PS: Curiously, when looking around for a solution to avoid threading
the values, I implemented a pseudo-dependent Map very similar to the
one Sean proposed earlier today. Just  an amusing coincidence :)

PS2: No grains of barley were harmed in the writing of the blog post.

On Wed, Jul 9, 2008 at 2:08 PM, James Iry <jamesiry@...> wrote:
> Here's somebody having fun (and getting drunk) with Scala's type system:
>
> http://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html
>



--
Rafael de F. Ferreira.
http://www.rafaelferreira.net/


Re: Re: [scala-user] Phantom types

by James Iry-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

No he hasn't.  See my comment.

http://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html

On Sun, Jul 13, 2008 at 8:09 AM, Rob Dickens <arctic.bob@...> wrote:
In exchange for type safety, it looks as though you have to give up the ability to build the end result in stages. See the comment (@rob) I've just added. Please correct me if I'm wrong.


Re: Re: [scala-user] Phantom types

by Rob Dickens-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

You are right. Well spotted.

On Sun, Jul 13, 2008 at 5:08 PM, James Iry <jamesiry@...> wrote:
No he hasn't.  See my comment.
On Sun, Jul 13, 2008 at 8:09 AM, Rob Dickens <arctic.bob@...> wrote:
In exchange for type safety, it looks as though you have to give up the ability to build the end result in stages. See the comment (@rob) I've just added. Please correct me if I'm wrong.