[Seaside] Brushes and state

James Foster Smalltalk at JGFoster.net
Fri Jun 19 14:11:56 UTC 2009


Julian,

Just to clarify your example a bit, let me know if I'm on the right  
track here... With a 2.9 Painter if you need to implement #updateRoot:  
then you need to be in the parent's #children. To be in the parent's  
children, you probably need to be in an instance variable and you  
probably need to be set up in the parent's #initialize method. Thus,  
your example below of creating the map during #renderContentOn: would  
not work.

To use a Painter or Component: (1) add an instance variable to the  
parent for each map; (2) initialize each instance variable in  
#initialize; (3) add each instance variable to #children; and (4) use  
the map in #renderContentOn:.

To use a Brush: (1) add one message send to your #updateRoot: for any  
number of maps; and (2) add any number of maps in #renderContentOn:.

Given that the map itself does not need any state, creating it as a  
component (I'm not familiar with the painter implications) seems to  
encourage reuse by inheritance rather than by delegation.

I mention these issues to describe my understanding and invite help,  
not to argue. I agree that the distinctions are a bit subtle and I  
don't need there to be a clear "right" answer.

James

On Jun 18, 2009, at 6:13 PM, Julian Fitzell wrote:

> So, with the need to update the root, I think this would work  
> equally well as a simple renderable object in 2.8 but it wouldn't  
> really be be much better than a component or brush.
>
> With a 2.9 Painter, you can implement #updateRoot: on the Painter  
> subclass itself so the map object would be able to encapsulate all  
> of that. This does require, as you point out, that the Painter be  
> added to #children, of course, but I think that's better than having  
> to implement your own root updating behaviour and not unexpected for  
> the user.
>
> Your renderContentOn: would look basically the same as your version  
> with either a painter or a renderable object:
>
> MyComponent>>#renderContentOn: html
>        html render: (GoogleMap new
>                class: 'myMap';
>                setCenter: 45.5267 @ -122.8390 zoom: 11;
>                "..."
>                yourself)
>
> So I think the result is slightly better with a Painter in the sense  
> of implementing #children, rather then update root behaviour.
>
> The other advantage is more theoretical and that is that a painter  
> is not dependent on the encapsulating component using Canvas as its  
> renderer. I say this is pretty theoretical because the only other  
> renderer right now is the RSS one. :) From an architectural point of  
> view, though, components are able to use any renderer they want and  
> if they're using one that doesn't support your brush, well they  
> couldn't easily use your implementation.
>
> This is all pretty subtle. Thus the debate. :)
>
> Julian
>
> On Thu, Jun 18, 2009 at 5:49 PM, James Foster  
> <Smalltalk at jgfoster.net> wrote:
> Julian,
>
> I did the GoogleMaps stuff several months ago and was only comparing  
> component and brush; I didn't consider a Painter mostly from lack of  
> knowledge (and being on a 2.8 environment). I wasn't aware that  
> there was a debate about when to use brushes; I thought it was just  
> me who couldn't figure it out!
>
> I ended up with a Brush because it felt more like I was just  
> defining a special <div> and I didn't want to require people to  
> define a child component. I figured that until I needed something  
> more complicated I'd stay with the simplest thing that could  
> possibly work (tm), and the brush approach came together nicely.  
> Once I started thinking about GoogleMaps as being little more than a  
> fancy div/listbox/image, several things fell out quite cleanly. I  
> discovered that I don't want to keep any state and that I want to  
> treat the configuration as one does with other things. For example  
> (where all of the messages to the brush are optional, but  
> #setCenter:zoom: is most useful):
>
> MyComponent>>#renderContentOn: html
>
>        html googleMap
>                class: 'myMap';
>                setCenter: 45.5267 @ -122.8390 zoom: 11;
>                enableGoogleBar;
>                addType: GMapType physical;
>                addControl: GControl largeMapControl;
>                setUIToDefault;
>                on: 'zoomEnd' do: [:x :y :z |
>                        'alert("Zoom from ' , x printString , ' to  
> ' , y printString ,
>                        ' (see GMUsingLatLong>>renderContentOn:)");'];
>                yourself.
>
> The only other requirement is that the component needs to allow some  
> #updateRoot: behavior:
>
> MyComponent>>#updateRoot: anHtmlRoot
>
>        super updateRoot: anHtmlRoot.
>        self updateRootWithGoogleMaps: anHtmlRoot.
>
> The implementation involves creating various scripts and feeding  
> them out, but it works fine in the brush.
>
> GoogleMap>>#with: anObject
>
>        self ensureId.
>        super with: [
>                anObject renderOn: canvas.
>                canvas html: self mapScript.
>        ].
>        self addLoadScript: self variable , 'Init()'.
>
> Overall it seemed less intrusive for the library client to use a  
> brush rather than a component. Other than #updateRoot:, there isn't  
> really much to do. With a component there were so many things that  
> were brush-like, including setting the class, id, style, etc., and  
> more issues (does it need to be included as a child?). I was able to  
> do so much without state, that it just seemed nice this way. It  
> seemed like I got further than any of the other GoogleMaps packages  
> I found, but I'd love to see another approach or get expert feedback  
> on what I've done.
>
> In general, while I'm heavily involved in Seaside from the GemStone  
> point-of-view, there is still a great deal for me to learn about  
> when to use different parts of the framework. This exercise was  
> another opportunity to learn and I did learn something!
>
> James
>
>
> On Jun 18, 2009, at 5:15 PM, Julian Fitzell wrote:
>
> James,
>
> It's been a while since I looked at the google maps stuff so I don't  
> recall... what do you actually render to the page? If memory serves,  
> you only need to output stuff that can be generated by the standard  
> brushes (divs and JS or something, right?) and you don't need to put  
> content inside it.
>
> I have no memory of whether there is anything that requires a  
> component to keep state but it doesn't *seem* at first glance to me  
> like something that needs to be a brush either. I don't mean to  
> suggest you're wrong since you've obviously gone through the  
> exercise and I haven't but there's quite a bit of debate now and  
> then over when to use brushes. I'm just wondering whether you  
> considered a renderable object (a Painter in 2.9) as an option or  
> just component/brush. And if you ruled out the third option, is  
> there a particular reason you think a brush is more appropriate?
>
> Julian
>
> On Thu, Jun 18, 2009 at 4:00 PM, James Foster  
> <Smalltalk at jgfoster.net> wrote:
> Mariano,
>
> I'll be interested to see how this comes out. As I mentioned  
> earlier, I started with a component and switched to a brush. I came  
> to view the GoogleMap as a browser widget, something like a listbox,  
> where you give it some data and let it draw itself. Yes, you can  
> configure callbacks, but that isn't really different from other  
> brushes. What sort of 'state' do you envision keeping with the map?  
> Might that be better in a domain-specific component that wraps a  
> map? I was able to implement over 40 examples and have not yet found  
> a need to get more complex.
>
> James
>
> On Jun 18, 2009, at 2:58 PM, Mariano Montone wrote:
>
> Thanks Julian. I think a component will be ok.
>
> Mariano
>
> On Thu, Jun 18, 2009 at 1:22 PM, Julian Fitzell <jfitzell at gmail.com>  
> wrote:
> Hi Mariano,
>
> Off the top of my head, if I were implementing a google maps  
> package, I would do it as a component or a painter (see below).  
> Brushes certainly aren't intended to be kept around so if you have  
> state to persist between requests that's not the way to go.
>
> There are people who like implementing everything as brushes but the  
> main functionality of brushes is that they can be selected in  
> arbitrary orders to nest content within each other, e.g.:
>
> html div: [ html span: [ html paragraph: 'foo' ] ].
>
> Unless you plan to do be able to do:
>
> html div: [ html googleMap: [ html paragraph: 'foo' ] ]
>
> (i.e. unless the thing you are creating allows content to be put  
> inside it) I don't think there's much advantage in making your own  
> brush. (The other reason to consider using brushes of course is that  
> they have more direct access to the document).
>
> Even if you don't need the benefits of components (see http://blog.fitzell.ca/2009/05/when-to-use-seaside-component.html 
>  ), you can just create a renderable object by implementing  
> #renderOn: and do:
>
> html render: (GoogleMaps new configSomeStuff; yourself)
>
> This process is made much clearer in 2.9 where you can subclass  
> WAPainter, implement #rendererClass to control what kind of renderer  
> you get passed (you might possibly implement the google maps thing  
> *using* one or more custom brushes and have your own renderer for  
> them), and implement #renderContentOn: as you would for a component.
>
> Hopefully that makes things clearer and not muddier. :)
>
> Julian
>
> On Thu, Jun 18, 2009 at 5:51 AM, Mariano Montone <marianomontone at gmail.com 
> > wrote:
> Hello!,
>           I'm implementing an API for rendering Google Maps. I've  
> decided to implement it as a brush. That's because I'm just  
> generating javascript code. But now I have a problem: when adding  
> support for callbacks, I need to hold some state; for example, the  
> map the callback refers to. But I think brushes are not meant to  
> hold state, that is something left for the components mechanism,  
> isn't it? So I would like to know what would be the correct way of  
> implementing it in the framework. Should I implement maps as  
> components, or should I add state to my brushes; I may hold a state  
> in the callback block too, but I don't think that's good.
>
> Thanks!
>
> Mariano
>
>
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/seaside/attachments/20090619/f81bf419/attachment.htm


More information about the seaside mailing list