Subclassing with Bloch’s Builder pattern, revised

So last year I posted about using Joshua Bloch’s Builder pattern to create objects from a hierarchy of subclasses.

I realized later that while I did have something like this completely working at one point, I had it working in C#, which has deceptively different generic semantics. (It also has named parameters, which makes the Builder pattern a fair bit less necessary.) As Zdenek Henek demonstrated (several weeks ago, sorry Zdenek!), in Java, the original version I posted doesn’t allow you to call the arguments in any order.

This one does:

class Shape
{
    private final double opacity;

    public double getOpacity ()
    {
        return opacity;
    }

    public static abstract class ShapeBuilder<S extends Shape, B extends ShapeBuilder<S, B>>
    {

        private double opacity;

        @SuppressWarnings( "unchecked" )
        public B opacity ( double opacity )
        {
            this.opacity = opacity;
            return (B) this;
        }

        public abstract S build ();
    }

    private static class DefaultShapeBuilder extends ShapeBuilder<Shape, DefaultShapeBuilder>
    {
        @Override
        public Shape build ()
        {
            return new Shape( this );
        }
    }

    public static ShapeBuilder<?, ?> builder ()
    {
        return new DefaultShapeBuilder();
    }

    protected Shape ( ShapeBuilder<?, ?> builder )
    {
        this.opacity = builder.opacity;
    }
}

class Rectangle extends Shape
{

    private final double height;
    private final double width;

    public double getHeight ()
    {
        return height;
    }

    public double getWidth ()
    {
        return width;
    }

    public static abstract class RectangleBuilder<S extends Rectangle, B extends RectangleBuilder<S, B>> extends ShapeBuilder<S, B>
    {
        private double height;
        private double width;

        @SuppressWarnings( "unchecked" )
        public B height ( double height )
        {
            this.height = height;
            return (B) this;
        }

        @SuppressWarnings( "unchecked" )
        public B width ( double width )
        {
            this.width = width;
            return (B) this;
        }
    }

    public static RectangleBuilder<?, ?> builder ()
    {
        return new DefaultRectangleBuilder();
    }

    protected Rectangle ( RectangleBuilder<?, ?> builder )
    {
        super( builder );
        this.height = builder.height;
        this.width = builder.width;
    }

    private static class DefaultRectangleBuilder extends RectangleBuilder<Rectangle, DefaultRectangleBuilder>
    {
        @Override
        public Rectangle build ()
        {
            return new Rectangle( this );
        }
    }
}

class RotatedRectangle extends Rectangle
{
    private final double theta;

    public double getTheta ()
    {
        return theta;
    }

    public static abstract class RotatedRectangleBuilder<S extends RotatedRectangle, B extends RotatedRectangleBuilder<S, B>> extends Rectangle.RectangleBuilder<S, B>
    {
        private double theta;

        @SuppressWarnings( "Unchecked" )
        public B theta ( double theta )
        {
            this.theta = theta;
            return (B) this;
        }
    }

    public static RotatedRectangleBuilder<?, ?> builder ()
    {
        return new DefaultRotatedRectangleBuilder();
    }

    protected RotatedRectangle ( RotatedRectangleBuilder<?, ?> builder )
    {
        super( builder );
        this.theta = builder.theta;
    }

    private static class DefaultRotatedRectangleBuilder extends RotatedRectangleBuilder<RotatedRectangle, DefaultRotatedRectangleBuilder>
    {
        @Override
        public RotatedRectangle build ()
        {
            return new RotatedRectangle( this );
        }
    }
}

class BuilderTest
{
    public static void main ( String[] args )
    {
        RotatedRectangle rotatedRectangle = RotatedRectangle.builder()
                .theta( Math.PI / 2 )
                .width( 640 )
                .height( 400 )
                .height( 400 )
                .opacity( 0.5d )
                .width( 111 )
                .opacity( 0.5d )
                .width( 222 )
                .height( 400 )
                .width( 640 )
                .width( 640 )
                .build();
        System.out.println( rotatedRectangle.getTheta() );
        System.out.println( rotatedRectangle.getWidth() );
        System.out.println( rotatedRectangle.getHeight() );
        System.out.println( rotatedRectangle.getOpacity() );
    }
}

Note though it requires some unchecked casts, and depends on the convention that each Builder’s generics are self-referential, which could present some risk if it’s extended further. Test early, test often.

The 21st century: ur doin it wrong

I know Oracle must be drilling way below the bottom of the barrel these days trying to find a way to monetize Larry Ellison’s vanity purchase get some return out of the Sun buyout, but hiding the JAX-RS specification under a bushel and charging US$50k to implement it commercially mostly strikes me as a great way to make sure no significant amount of RESTful web service development ever gets done in Java.

(Comments closed due to spam.)

Fun, or rather no fun, with generics (updated)

So, I understand that the following doesn’t work, but why doesn’t it work?

interface Adapter {}

class Adaptulator<I> {
    <e, A extends I & Adapter> void add(Class extl, Class<A> intl) {
    	addAdapterFactory(new AdapterFactory(extl, intl));
    }
}

The add() method gives me a compile error, “Cannot specify any additional bound Adapter when first bound is a type parameter” (in Eclipse), or “Type parameter cannot be followed by other bounds” (in IDEA), take your pick.

Clearly you’re just Not Allowed to use the type parameter I there, before the &, and that’s that. (And before you ask, it doesn’t work if you switch ’em, because there’s no guarantee that I isn’t a concrete class.) But why not? I’ve looked through Angelika Langer’s FAQ and can’t find an answer.

Generally when some generics limitation seems arbitrary, it’s because you’ve created a situation where the type system can’t actually enforce correctness. But I don’t see what case would break what I’m trying to do here. I’d say maybe it has something to do with method dispatch after type erasure, but there’s only one add() method, so it’s not like there’s any ambiguity…

So what’s the problem?


Update: I cross-posted this to stackoverflow.com, and Bruno De Fraine pointed out that the reason multiple bounds were introduced in the first place was to control the erasure. Since I is just going to erase to Object, it doesn’t get you anything there. Unfortunately, all I wanted was the compile-time type safety, so I’ll have to come up with something else…

Come on aboard, I promise you you won’t hurt the horse

Another bandwagon I haven’t jumped on is REST. It’s amazing how many words you can read about a technical subject without being sure if you’ve actually learned anything or not. But this Dare Obasanjo post made a bit more sense. Apparently in a REST architecture:

  1. interaction is client-server
  2. communication between client and server is stateless
  3. requests [is that a typo? does he mean responses?] are either cacheable, or not, and marked as such.
  4. [mumble mumble jargon genitives technobabble]
  5. there can be multiple layers (proxies, gateways, etc.) betwen client and server without the client or server having to know or care

That all seems pretty straightforward, and not really deserving of a sweet piece of technical nounage like representational state transfer. Perhaps the devil is in the one point that’s slightly less straightforward than the others? I’ll let you guess which one that is.

No, I’ll just quote Obasanjo directly.

there is a uniform interface between components which allows them to communicate in a standard way but may not be optimized for specific application scenarios. There are four interface constraints:

  1. identification of resources;
  2. manipulation of resources through representations;
  3. self-descriptive messages; and,
  4. hypermedia as the engine of application state.

(Emphasis in original; numbered points broken out by yours truly.)

Oh, and he was doing so well! It’s not obvious to me what any of these mean, and it’s even less obvious what they might mean as constraints. “Identification” is not a constraint. “…through representations” might be a constraint, but it seems like a pretty trivial one to me — how, in the client-server system described above, is a client going to manipulate (or even see) any resource except via some representation? I guess “self-descriptive” could be a constraint, though having worked with a number of people who claimed to write self-documenting code, it seems to me to be a constraint loose enough to drive a truck through. I might understand the last one if I knew what “hypermedia” and “engine” were supposed to mean in this context. Then again, I might not.

Luckily for us Obasanjo does go on to address these in more detail. As far as I can tell, they translate to:

  1. Give everything a URI.
  2. Use well-known data types / formats.
  3. Make proper use of protocol headers, error codes, etc.
  4. Use links, not cookies.

Okay, I think I’m starting to get it. (1)-(3) lay out a sort of minimalist program for web services, one I think I could get behind, in principle. It certainly sounds more fun than generating SOAP stubs and skeletons. (4) is the interesting one. On the one hand, it follows logically from “stateless” — or would, if all us Java EE developers weren’t used to thinking of state(less|ful)ness as a property of the server. On the other hand, true statelessness is hard for a procedural / OO programmer to wrap your head around.

“This is probably the most controversial and least understood of the architectural constraints set forth in Roy Fielding’s dissertation,” says Obasanjo, and I’m not surprised. Because, Fielding’s cogent arguments against cookies aside… the problem of representing state with URIs looks, to me, a whole lot like the problem of representing state with functions.

Comments closed due to spam.

His code not ‘functional’ or ‘elegant’

In the middle of another gold card, this one on Actors (PDF), a concurrent programming abstraction that Scala borrowed from Erlang. The Scala short tutorial on actors isn’t much help, at least not to someone who’s spent as little time with Scala as I have; mostly Mr. Haller just seems to show you the source code from the examples directory and say “see”? But I persevere.

In the course of said perseverance, I did run across one interesting link, which I post by way of bookmarking: Functional Java, “an open source library that aims to prepare the Java programming language for the inclusion of closures [and] serves as a platform for learning functional programming concepts by introducing these concepts using a familiar language.” Which sounds like exactly what Code Monkey needs.

Imperative knowledge

As part of my ongoing project to get a do-over on my misspent youth, I’ve started reading the lecture notes for MIT’s EECS 6.001: Structure and Interpretation of Computer Programs.

And I have to say: damn.

I mean, I actually feel like I’m learning something from about Slide Four. Contrast this with the freshman introductory C course I dropped in week one (I wanted to program Macs, not VT100s! — I was an awful hacker), and I can really see why smart people complain that CS is turning into Java vocational training. It’s not at MIT, but it was already on its way (to vocational training, I mean; Java wasn’t yet a twinkle in James Gosling’s eye) when I was at UCSC.

Which is probably one reason I ended up a Japanese major. And that it took me six years after high school to get back to programming. If they’d made CS sound half as interesting as linguistics…

Anyway, I’m hoping to go through the whole course, and write it up as I go. My track record on projects like this is not stellar, but we’ll see. I wish there was someone I could pay to grade me on it.

Meanwhile, speaking of writeups and track records, I still haven’t written up the monad project, but I did throw together a Scala “brush” for Alex Gorbachev’s syntax highlighter (basically just the Java brush with a different set of keywords and an extra regex for the non-alphabetic keywords like => and <: that confuse the regex engine, but it works) so when I do finish writing it up there will be pretty-printed examples:

package pizza;

object ListExample {
  def main(args: Array[String]) {

    val list = List(1, 2, 3)
    println(list)
    println(list map { x => x * 2});
  }
}

(Also I managed, for purely decorative purposes, to work this diagram into the novelette I finished drafting this weekend. I think for the final version I might prefer this one — it’s fancier, and less completely unrelated to what’s going on in the text than the other one. But I’m not sure I can be arsed recreating it in Illustrator. It seems like I ought to be able to just generate a PDF from the TeX source and use that, but when I try — I have only the barest exposure to TeX — I only get error messages.)

Substantial forms of being

So I gave my pizza lunch talk on monads today, having over the past couple of weeks snuck in considerably more than a single Gold Card day’s worth of work. I think it went fairly well and was mostly comprehensible, though on the comprehensibility front it probably helped that a lot of my statements were wrapped in “I’m not sure what…”, “I’m not sure whether…” and “I’m not sure why…” —

— which, if you think about it, is really just a kind of Option (a.k.a. Maybe), so it’s totally appropriate.

At least, that’s (provisionally) my story and I’m (for now) sticking to it.

I got as far (I think) as figuring out what a monad is (mostly), and (I think) how the Scala List and Option monads work (mostly), largely by porting (partially) List and Option to Java. I mean to turn the talk into a post here, but that’ll take a couple of days — maybe longer if I get ambitious about cleaning up the code examples.

What I didn’t get to in any detail was Dan’s question about state, which was sort of the main point of this investigation, along with I/O and error handling. Always leave yourself some work for tomorrow, I’ve been told….